当前位置: 首页 > news >正文

GJOI 11.11 题解

不知道哪里来的题目,感觉质量一般。听说是广大附中交换过来的。

1.洛谷 P1031 NOIP2002 均分纸牌 加强版

题意

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

思路

先研究要怎么相互给牌,记应该拿到的牌为 need=∑i=1nainneed=\dfrac{\sum\limits_{i=1}^na_i}{n}need=ni=1nai

  • need≤aineed\le a_ineedai:把自己的牌给后面的人;
  • need>aineed>a_ineed>ai:看 i+1i+1i+1 的牌是否 ≥need−ai\ge need-a_ineedai,如果不能就继续往后找——直到有一个 xxxax≥∑t=inneed−aia_x\ge \sum\limits_{t=i}^nneed-a_iaxt=inneedai,即找到一个人能够补足前面的人所有空缺,然后直接跳到 xxx

这么看,时间复杂度均摊下来是 O(n)O(n)O(n)。而题目要求移动的字典序最小,因此可以想到答案应该长成:

  • 一对 x→yx\to yxy 至多出现一次;
  • 理想情况是 i→i+1i\to i+1ii+1,如果 need>aineed>a_ineed>ai 就找到那个 xxx,然后 x→x−1x\to x-1xx1x−1→x−2x-1\to x-2x1x2,……,i+1→ii+1\to ii+1i

因为要先输出最小操作次数,所以就按照相互给牌的方法去模拟(即洛谷 P1031),记 bi=ai−needb_i=a_i-needbi=aineedti=1/−1t_i=1/-1ti=1/1iiii+1i+1i+1 的操作标记(决定是 i→i+1i\to i+1ii+1 还是 i+1→ii+1\to ii+1i),按照 bib_ibi 的正负分类决定 tit_iti,每次都 bi+1←bib_{i+1}\leftarrow b_ibi+1bi

然后就是像上文那样模拟方案。具体细节见代码。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=3e5+9;
ll n,a[N],b[N];
ll t[N];
ll sum;
int main()
{scanf("%lld",&n);for(int i=1;i<=n;i++){scanf("%lld",&a[i]);sum+=a[i];}ll cnt=0;ll need=sum/n;bool flag=1;for(int i=1;i<=n;i++){b[i]=a[i]-need;if(b[i])flag=0;}if(flag){puts("0");return 0;}for(int i=1;i<=n;i++){if(b[i]>0){b[i+1]+=b[i];b[i]=0;t[i]=1;cnt++;}else if(b[i]<0){b[i+1]-=abs(b[i]);b[i]=0;cnt++;t[i]=-1;}else continue;}//其实求cnt和方案可以放一起,只是懒得存答案了printf("%lld\n",cnt);for(ll i=1;i<=n;i++)//保证i-1都处理好了{if(t[i]==1){printf("%lld %lld %lld\n",i,i+1,a[i]-need);a[i+1]+=a[i]-need;a[i]=need;}if(t[i]==-1){if(need-a[i]<=a[i+1])//i+1 可以承担 i 的补足{printf("%lld %lld %lld\n",i+1,i,need-a[i]);a[i+1]-=need-a[i];a[i]=need;}else //向后找到一个 x=pos,可以承担前面所有{ll pos=i,sum=0;while(pos<=n&&(t[pos]==-1&&sum+need-a[pos]>a[pos+1])){sum+=need-a[pos];pos++;}sum+=need-a[pos];for(ll j=pos;j>=i;j--){printf("%lld %lld %lld\n",j+1,j,sum);a[j+1]-=sum;sum-=need-a[j];a[j]+=sum;}i=pos;//前面都处理完了,直接跳到后面}}}return 0;
}

2.吞噬变异

题意

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

思路

终于自想到一道建模题了。

考虑模拟一种“松弛操作”,设 fif_ifi 表示得到异兽 iii 的最小花费,有初始化 fi=aif_i=a_ifi=ai,然后对于可以合成异兽 xxxu,vu,vu,v 建边,然后不断跑 spfa 或 dijkstra:

如果 fu+fv<fxf_u+f_v<f_xfu+fv<fx,那么 fxf_xfx 被更新,xxx 和某只异兽 yyy 能够合成的异兽 zzz 可能可以更新,于是把 xxx 扔进(优先)队列即可。

时间复杂度 O(n?)/O(nlog⁡n)O(n?)/O(n\log n)O(n?)/O(nlogn)。下面给出 spfa 的实现。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pll pair<ll,ll>
#define mk make_pair
#define fi first
#define se second
const ll N=1e5+9;
ll n,m,a[N];
struct edge
{ll to,next,pas;
}e[N<<1];
ll idx,head[N];
void addedge(ll u,ll v,ll pas)
{idx++;e[idx].to=v;e[idx].next=head[u];e[idx].pas=pas;head[u]=idx;
}
ll f[N];
void spfa()
{queue<pll>q;for(int i=1;i<=n;i++){f[i]=a[i];q.push(mk(a[i],i));}while(!q.empty()){pll tem=q.front();q.pop();ll u=tem.se;for(int i=head[u];i;i=e[i].next){ll v=e[i].to,pas=e[i].pas;if(f[u]+f[v]<f[pas]){f[pas]=f[u]+f[v];q.push(mk(f[pas],pas));}}}
}
int main()
{scanf("%lld%lld",&n,&m);for(int i=1;i<=n;i++)scanf("%lld",&a[i]);for(int i=1;i<=m;i++){ll u,v,pas;scanf("%lld%lld%lld",&u,&v,&pas);addedge(u,v,pas);addedge(v,u,pas);}spfa();for(int i=1;i<=n;i++)printf("%lld ",f[i]);return 0;
}

3.连线问题

题意

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路

还原出每个点的坐标,对 y=ay=ay=a 那列的每个横坐标 xaixa_ixai,贪心地在 xbixb_ixbi 上二分第一个 ≥\ge 它的和第一个 ≤\le 它的,然后跑 MST。

为什么这样建边就是最优的?假使现在就只有 xaixa_ixai,第一个比 xaixa_ixai 大的 xbjxb_jxbjxbj+1xb_{j+1}xbj+1,同样都要连接 xbj→xbj+1xb_j\to xb_{j+1}xbjxbj+1,显然 xai→xbjxa_i\to xb_jxaixbj 的长度要短于 xai→xbj+1xa_i\to xb_{j+1}xaixbj+1(三角函数)。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define dd double
const ll N=6e5+9;
ll n,m,t;
dd a0,b0;
dd aa[N],bb[N];
struct bian
{ll u,v;dd w;
}b[N<<2];
bool cmp(bian x,bian y)
{return x.w<y.w;
}
ll fa[N<<1];
ll fz(ll x)
{while(x!=fa[x])x=fa[x]=fa[fa[x]];return x;
}
dd Dis(ll xa,ll ya,ll xb,ll yb)
{return sqrt((xa-xb)*(xa-xb)+(ya-yb)*(ya-yb));
}
dd kruskal()
{for(int i=1;i<=n+m;i++)fa[i]=i;sort(b+1,b+t+1,cmp);dd ret=0;ll cnt=0;for(int i=1;i<=t;i++){ll fu=fz(b[i].u),fv=fz(b[i].v);if(fu==fv)continue;fa[fu]=fv;ret+=b[i].w;cnt++;if(cnt==n+m-1)break;}return ret;
}
int main()
{scanf("%lld%lld%lf%lf",&n,&m,&a0,&b0);ll tot=0;dd curx=0;for(int i=1;i<=n;i++){dd x;scanf("%lf",&x);curx+=x;aa[i]=curx;if(i>1)b[++t]=(bian){i-1,i,x};}curx=0;for(int i=1;i<=m;i++){dd x;scanf("%lf",&x);curx+=x;bb[i]=curx;if(i>1)b[++t]=(bian){i-1+n,i+n,x};}for(int i=1;i<=n;i++){//第一个大于的 if(aa[i]<bb[m]){ll pos=upper_bound(bb+1,bb+m+1,aa[i])-bb;b[++t]=(bian){i,pos+n,Dis(aa[i],a0,bb[pos],b0)};}//第一个小于等于的 if(aa[i]>=bb[1]){ll pos=upper_bound(bb+1,bb+m+1,aa[i])-bb-1;b[++t]=(bian){i,pos+n,Dis(aa[i],a0,bb[pos],b0)};}}printf("%.2lf",kruskal());return 0;
}

4.走迷宫

题意

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

http://www.dtcms.com/a/611854.html

相关文章:

  • C语言编译器 | 如何选择适合自己的编译器进行开发
  • 广东省交通建设监理检测协会网站怎么做自己的网站赚钱
  • (论文速读)AIMV2:一种基于多模态自回归预训练的大规模视觉编码器方法
  • 蓝牙 Prmary PHY LE Coded 收发测试发送没问题,但接收不到,是否是硬件不支持
  • 网站备案需要多少时间企业建设网站应如何申请
  • 商城网站建设公司报价番禺制作网站技术
  • 电商网站开发研究内容和预期成果扬中市人才网官网
  • 天保建设集团有限公司网站天津多媒体设计公司
  • 重庆网捷网站建设技术有限公司wordpress如何设置关键词
  • 舞美设计制作公司sem与seo的区别
  • 数字营销软件逆冬seo
  • 网站整站下载带数据库后台的方法大连百度推广公司有几家
  • 数学分析简明教程——4.2
  • 物联网网站开发网站建设一般用英文怎么说
  • 红旗渠建设集团有限公司网站注册一个公司网站的费用
  • 台州网站关键字优化详情网络销售是做什么的
  • 学校网站建设答辩php 5.4 wordpress
  • AI大模型参数
  • 数据库练习查询5
  • wordpress摘要开启做网站建设优化的公司
  • 中国建设招标网是什么网站有没有做美食的规模网站
  • 网站制作计划可以做兼职的网站
  • 网站开发需要哪些能力公众号关注推广
  • 四川省城市建设培训中心 网站义乌开锁做网站哪个好
  • 做网站上传服务器品牌设计包括哪些方面
  • 外贸高端网站开发wordpress 广告 插件
  • 网站开发时间进度表网站推广如何做
  • 怎么做淘宝联盟网站推广宁波seo怎么选
  • 个人简历网站模板下载四川省建设厅官方网站信息查询
  • 广州城市职业学院门户网站网络营销是什么学科门类