2017年8月30日 机房模拟赛题解
来源:互联网 发布:网络电视有哪些功能 编辑:程序博客网 时间:2024/05/21 21:37
写在前面233:
这场模拟赛不是特别地难,t1的模拟其实坑很多,t2的二分答案加贪心不是特别难想,但也不是很简单,t3是一道非常有意思的题目。这些貌似都是Codeforces的原题233
t1:题解里面写的是去讨论所有不一样的情况会有多少种可能,但是实际上不需要这样,因为如果可能是possible的话,注意到题目中的
#include<cstdio>#include<cstring>#include<iostream>using namespace std;const int MAXN=100000*5;int n,a[MAXN],cntb[MAXN],cnta[MAXN],arc[MAXN],loc1,loc2,cnt,num,b[MAXN],cn;int main(){ freopen("seq.in","r",stdin); //freopen("seq.out","w",stdout); scanf("%d",&n); for(register int i=1;i<=n;i++){ scanf("%d",&a[i]); cnta[a[i]]++; if(cnta[a[i]]==1) arc[a[i]]=i; if(cnta[a[i]]==2){ cnt++;loc1=arc[a[i]];loc2=i; } if(cnta[a[i]]==3){ printf("Impossible\n"); return 0; } } if(cnt>=2||cnt==0){ printf("Impossible\n"); return 0; } cnt=0; for(register int i=1;i<=n;i++){ scanf("%d",&b[i]); cntb[b[i]]++; if(cntb[b[i]]==2) cnt++; if(cntb[b[i]]==3){ printf("Impossible\n"); return 0; } } if(cnt>=2||cnt==0){ printf("Impossible\n"); return 0; } for(register int i=1;i<=n;i++){ if(cnta[i]==0){ num=i;break; } } if(a[loc1]>num) a[loc1]=num; else a[loc2]=num; bool judge=true; for(register int i=1;i<=n;i++){ if(b[i]!=a[i])cn++; if(cn>=2){judge=false;} } if(judge){ for(register int i=1;i<=n;i++){ printf("%d\n",a[i]); } return 0; } cn=0; int tmp=a[loc1];a[loc1]=a[loc2];a[loc2]=tmp; for(register int i=1;i<=n;i++){ if(b[i]!=a[i])cn++; if(cn>=2){ printf("Impossible\n"); return 0; } } for(register int i=1;i<=n;i++){ printf("%d\n",a[i]); } return 0;}/*55 4 5 3 14 4 2 3 1*/
显然有很多的重复语句,代码也不是很精简,也没有缩行,本来是40行的代码被我写成了70多行
t2的话,我们显然可以得到一个二分答案+贪心的做法(…这么显然的东西我考试的时候都没有想到,而且他们乱贪都贪了70分,太水了数据,早知道就直接乱贪了…)
算法:由于发现一个性质,一定是从左边开始找会更优,这个意思是说,如果一个点A在点B的左边,那么如果点A的打卡机在C点,C点位于A点的左侧,而B点的打卡机位于D点,如果D点在C点的左侧,显然是不优的,这个时候至少应该让A点去用D作为打卡机,而B点取去用C作为打卡机更为优秀,所以我们的算法是,先二分一个每个点从自己到自己的打卡机再到公司的距离和的最大值,显然 我们在对每一个点进行枚举的时候,贪心地思考,让从左至右第一个打卡机使其满足二分的答案的作为他的打卡机,这样一来可以让后面的更为优秀而不是再去更左边找打卡机,所以我们只需要一个Lperson和Lmachine指针即可,然后最后判一下是不是每个人都可以在规定的距离内走到公司,二分即可。
代码:
#include<cstdio>#include<iostream>#include<algorithm>#include<cmath> using namespace std;int n,m;long long x,a[500000],b[500000];bool check(long long mid){ int Lperson=1,Lmachine=1; while(Lperson<=n&&Lmachine<=m){ if(abs(a[Lperson]-b[Lmachine])+abs(x-b[Lmachine])<=mid){Lperson++;Lmachine++;} else {Lmachine++;} } if(Lperson==n+1) return true; else return false;}int main(){ freopen("work.in","r",stdin); freopen("work.out","w",stdout); scanf("%d%d%lld",&n,&m,&x); for(register int i=1;i<=n;i++)scanf("%lld",&a[i]); for(register int i=1;i<=m;i++)scanf("%lld",&b[i]); sort(a+1,a+n+1);sort(b+1,b+m+1); long long l=0,r=2000000000; while(l<=r){ long long mid=(l+r)>>1; if(check(mid))r=mid-1; else l=mid+1; } printf("%lld\n",r+1); return 0;}
t3稍微有一些难(虽然对于我来说是极其难)。
首先我们需要做的事情是让每一条边的权值改变成一个最大的数使得其出现在原图中的任意一个最小生成树中。那么首先我们做一遍最小生成树,然后重新把这个最小生成树建出来,建成一棵新的树,然后显然我们可以得到一棵新的漂亮的树形结构,对于原图中的一条边,如果没有出现在这棵新的树里,那么显然对于这条边的两个端点u和v,他们分别到lca的这段区域内,寻找一个最大的值,因为寻找到的这个最大的值原来就在最小生成树上面,那么我们只需要把这条边的权值设置成这个最大值的值减一就可以了。因为如果是和最大值相等的话,那么我们在选取边的时候,既可以选择这条边,也可以选择和其权值一样的边,不能保证在任何一个生成树中都可以出现这条边。
现在要新加入的边(u,v)显然权值应该最大为路径u-lca(u,v)-v的最大值减一,否则就没有“竞争力”了。
那么对于在原来的生成树上的边,我们该怎么处理呢?首先有很多很多不在原来的生成树上的边会对其造成影响,那么显然我们应该把这些边的ans全部改变,什么意思呢?我来举个例子。
显然我们对于x到LCA(U,V)这条边,(U,V)的这条边是有可能对其造成影响的,为什么呢?因为我们最开始做的最小生成树,可能只是其中的一种最小生成树,那么假如我的(U,V)的权值等于X到LCA(U,V)的权值呢?我们甚至还会发现,假如X-LCA(U,V)的权值大于(U,V)的权值,也有可能会选中前者而不选后轴,这里也举一个例子。
此时的x,y,z分别是几已经连通的块,显然我们会选择8这条边和10这条边来让其连通,但是选了10却没有选9这条边,所以我们的做法是,对于每一条不在原来的生成树上的边,我们去修改其两个端点到LCA的路径上的所有边的答案,最后如果这个答案还是inf的话,那么说明这条边无论为多少都不会被改变。
修改的时候我们用一个并查集来修改,这是很巧妙的思想,由于我们的边是先排了序的,那么我们先去讨论的不在原来的生成树上的边一定是更小的,因此由于我们是取min值,所以后面讨论的边如果之前已经更新过某段区间了,那么一定是不会再更新到这段区间的。因此我们可以用并查集(路径压缩)来进行优化,时间大大减少,这道题好像是Codeforces 827D还是什么的,没在cf上交过,本地过了,教师端的评测机也过了。
代码:
#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#define P 18const int MAXN=400005;const int inf=1000000000;using namespace std;int fa[MAXN],n,m,to[MAXN],ans[MAXN],anc[P+5][MAXN],dep[MAXN],head[MAXN],tail,mx[P+5][MAXN];struct Edge{int to,flow,nxt,id;}edge[MAXN*2];struct Line{int from,to,flow,id;}line[MAXN]; bool used[MAXN];bool cmp(const Line& A,const Line& B){return A.flow<B.flow;}int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}void insert(int from,int to,int flow,int id){ edge[++tail].to=to;edge[tail].nxt=head[from];head[from]=tail;edge[tail].id=id;edge[tail].flow=flow; edge[++tail].to=from;edge[tail].nxt=head[to];head[to]=tail;edge[tail].id=id;edge[tail].flow=flow;}void dfs(int u,int fa,int num){ dep[u]=dep[fa]+1;anc[0][u]=fa;mx[0][u]=num; for(register int i=1;i<=P;i++){ anc[i][u]=anc[i-1][anc[i-1][u]]; mx[i][u]=max(mx[i-1][anc[i-1][u]],mx[i-1][u]); } for(register int i=head[u];i;i=edge[i].nxt){ int v=edge[i].to; if(v^fa){ to[edge[i].to]=edge[i].id; dfs(edge[i].to,u,edge[i].flow); } }}int lca(int x,int y,int &d){ d=0;if(dep[x]<dep[y])swap(x,y); for(register int i=P;i>=0;i--){ if(dep[anc[i][x]]>=dep[y]){ d=max(d,mx[i][x]); x=anc[i][x]; } } if(x==y)return x; for(register int i=P;i>=0;i--){ if(anc[i][x]^anc[i][y]){ d=max(d,max(mx[i][x],mx[i][y])); x=anc[i][x];y=anc[i][y]; } } d=max(d,max(mx[0][x],mx[0][y])); return anc[0][x];}void solve(int x,int lca,int d){ x=find(x); while(dep[x]>dep[lca]){ ans[to[x]]=min(ans[to[x]],d); int y=find(anc[0][x]); fa[x]=y; x=find(x); }}int main(){ scanf("%d%d",&n,&m); for(register int i=1;i<=m;i++)scanf("%d%d%d",&line[i].from,&line[i].to,&line[i].flow),line[i].id=i; sort(line+1,line+m+1,cmp);for(register int i=1;i<=n;i++)fa[i]=i; for(register int i=1;i<=m;i++){ int p=find(line[i].from),q=find(line[i].to); if(p^q){used[i]=1;fa[p]=q;insert(line[i].from,line[i].to,line[i].flow,line[i].id);} } dfs(1,0,0);memset(ans,63,sizeof(ans)); for(register int i=1;i<=n;i++)fa[i]=i; for(register int i=1;i<=m;i++){ if(!used[i]){ int u=line[i].from,v=line[i].to,fa=lca(u,v,ans[line[i].id]); ans[line[i].id]--; solve(u,fa,line[i].flow-1);solve(v,fa,line[i].flow-1); } } for(register int i=1;i<=m;i++)if(ans[i]>inf) puts("-1"); else printf("%d\n",ans[i]); return 0;}
- 2017年8月30日 机房模拟赛题解
- 9月30日机房模拟赛题解
- 2017年9月2日 机房模拟赛
- 机房模拟赛 2017年9月26日 数据结构
- 机房模拟赛 2017年9月27日
- 2017年 10 月 9 日 机房模拟赛
- 2017年6月30日 在5427机房
- 7月22日训练赛题解
- 2015年9月12日模拟赛总结
- 07年NOIp模拟赛by Matrix67 定于10月5日上午8:30-11:30进行
- 机房训练赛 4月6日 (数论)
- 8月13日GDOI模拟总结
- 2017年8月16日(模拟一1976,1977,1978模拟、找规律、树形DP)
- 8月30日
- 2014年1月14日训练赛D题题解(栈+dfs)
- 2015年4月25日浙江省ACM比赛题解
- 2017年8月30日23:43:42
- 2017年8月15日(模拟7smoj2063,2064,2065暴力、动态规划、数学方法)
- http的七层协议
- 无向图的实现
- Pycharm使用-添加文件模版
- BigDecimal的加减乘除及比较大小
- 【leetcode】124.Binary Tree Maximum Path Sum
- 2017年8月30日 机房模拟赛题解
- # VSCode 编辑器
- java中Map<String,Double>map按照value降序排列 Map<String,Double>map=new TreeMap<String,Double>(); map.put("
- Springmvc中提交from之后不跳转不进控制器
- 从矛盾中解决市场
- 有向图的实现
- 每日英语阅读(四十四)
- 怎么下载小程序二维码-微信小程序开发-视频教程4
- 指针运算