Codeforces Round #408(div.2)
Posted FallDream
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #408(div.2)相关的知识,希望对你有一定的参考价值。
来自FallDream的博客,未经允许,请勿转载,谢谢。
凌晨打比赛真的难受,十一点趴下去,一觉起来感觉精神非常迷糊 脑子不好使了
------------------------------------------------------------------------------
A. Buying A House
给定n个点,每个点有一个价格。你有一些钱,你要求钱够买的情况下,离一个特殊点的最近距离。
小模拟
#include<cstdio> #include<iostream> #include<cstring> #include<map> #include<queue> #include<algorithm> #include<set> #include<cmath> #define MN 10005 #define INF 200000000 using namespace std; int read() { int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘) f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘; ch=getchar();} return x*f; } int n,s[MN+5],m,ans=INF,k; int abs(int x){return x<0?-x:x;} int main() { n=read();k=read();m=read(); for(int i=1;i<=n;i++)s[i]=read(); for(int i=1;i<=n;i++)if(s[i]&&s[i]<=m) ans=min(ans,abs(k-i)); printf("%d\n",ans*10); return 0; }
B. Find The Bone
有n个位置,一个球放在位置1,有m个位置有洞。k个操作,每次交换两个位置的东西,如果球到了洞上面,他就会掉下去,求球的最后位置。
大模拟
#include<cstdio> #include<iostream> #include<cstring> #include<map> #include<queue> #include<algorithm> #include<set> #include<cmath> #define MN 1000005 #define INF 200000000 using namespace std; int read() { int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘) f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘; ch=getchar();} return x*f; } int n,m,k,pos=1; bool b[MN+5]; int main() { n=read();m=read();k=read(); for(int i=1;i<=m;i++)b[read()]=1; if(b[1])return 0*puts("1"); for(int i=1;i<=k;i++) { int u=read(),v=read(); if(u==pos) { pos=v;if(b[v])return 0*printf("%d\n",v); } else if(v==pos) { pos=u;if(b[u])return 0*printf("%d\n",u); } } printf("%d\n",pos); return 0; }
C. Bank Hacking
有一棵n个节点的树,每个节点有一个权值,你要先选择一个节点,然后破坏它,与这个点连通且距离小等于2的点权值+1,然后你不断选择一个已经破坏的点的相邻节点破坏,求破坏的最大权值的最小值 n<=300000
很容易发现是选择一个点不变,与他相邻的+1,其它+2,取一个最大值。所以可以直接暴力枚举,算一下有多少个最大值和 与每个点相邻的最大值有几个 就可以轻松算出答案。
我菜,写了线段树。
#include<cstdio> #include<iostream> #include<cstring> #include<map> #include<queue> #include<algorithm> #include<set> #include<cmath> #define ll long long #define N 524288 #define MN 300005 #define INF 2000000000 using namespace std; int read() { int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘) f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘; ch=getchar();} return x*f; } struct edge{int to,next;}e[MN*5]; int cnt=0,n,a[MN+5],head[MN+5],ans=INF; int T[MN*10]; void renew (int x,int ad) { T[x+=N]=ad; for(x>>=1;x;x>>=1) T[x]=max(T[x<<1],T[x<<1|1]); } int query(int l,int r) { int sum=-INF; for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1) { if(~l&1) sum=max(sum,T[l+1]); if( r&1) sum=max(sum,T[r-1]); } return sum; } void ins(int f,int t) { e[++cnt]=(edge){t,head[f]};head[f]=cnt; e[++cnt]=(edge){f,head[t]};head[t]=cnt; } int main() { n=read(); memset(T,128,sizeof(T)); for(int i=1;i<=n;i++) a[i]=read(),renew(i,a[i]+2); for(int i=1;i<n;i++) { int x=read(),y=read(); ins(x,y); } for(int x=1;x<=n;x++) { renew(x,a[x]); for(int i=head[x];i;i=e[i].next) renew(e[i].to,a[e[i].to]+1); ans=min(ans,query(1,n)); renew(x,a[x]+2); for(int i=head[x];i;i=e[i].next) renew(e[i].to,a[e[i].to]+2); } printf("%d\n",ans); return 0; }
D.给定一棵树,一些节点是特殊节点,满足所有点到最近的特殊节点的距离不超过d,你要删去尽可能多的边,并且保证这个条件依旧满足,输出删去的数量和方案。
考虑从每个特殊节点开始bfs,如果一条边到的节点已经被bfs到了,删掉它。注意去重。
#include<cstdio> #include<iostream> #include<cstring> #include<map> #include<queue> #include<algorithm> #include<set> #include<cmath> #define ll long long #define MN 300005 #define INF 200000000 using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘) f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘; ch=getchar();} return x*f; } struct edge{int to,next;}e[MN*5]; int cnt=1,n,k,mx,head[MN+5],d[MN+5],num,q[MN+5],sum=0,fa[MN+5],ans[MN+5]; void ins(int f,int t) { e[++cnt]=(edge){t,head[f]};head[f]=cnt; e[++cnt]=(edge){f,head[t]};head[t]=cnt; } int main() { n=read();k=read();mx=read(); memset(d,42,sizeof(d)); for(int i=1;i<=k;i++) { int x=read();if(d[x]<INF)continue; q[++num]=x;d[x]=0; } for(int i=1;i<n;i++) ins(read(),read()); for(int i=1;i<=num;i++) for(int j=head[q[i]];j;j=e[j].next) if(e[j].to!=fa[q[i]]) { if(d[e[j].to]<INF) sum+=ans[j>>1]^1,ans[j>>1]=1; else d[q[++num]=e[j].to]=d[q[i]]+1,fa[e[j].to]=q[i]; } printf("%d\n",sum); for(int i=1;i<n;i++) if(ans[i]) printf("%d ",i); return 0; }
E 有n道题,你可以偷看p次答案,每次只能看连续的k道题。但是你只能看相邻的两个人,并且这些人不一定都是对的。
给出n,p,k和两个人分别有哪些题使得对的,求最多能看对(#滑稽)几道题 n,p<=1000 k<=50
考虑dp,用f[i][j][x][y]表示前i道题,看了j次,第一个人还能看x道题,第二个人还能看y道题。每次转移i后移一格之后,x,y都会-1(如果它不是0),也就是说看了这一题。当然,你也可以选择让j+1使得x和y变成k-1,也就是从这里开始看,后面的k-1道题当然都能看到啦。(感觉讲的不清不楚)
这样复杂度就是$O(npk^{2})$,不能通过此题,但是我们发现$p\geqslant 2\lceil\frac{n}{k}\rceil$的时候,我一定能看到所有题,只要这两个人有人做对了它。
这样p最大变成2n/k,复杂度降低为$O(n^{2}k)$,足够通过。空间的话,我们把第一维滚动一下呗。
#include<iostream> #include<cstdio> #include<cstring> #define INF 30000 using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < ‘0‘ || ch > ‘9‘){ if(ch == ‘-‘) f = -1; ch = getchar();} while(ch >= ‘0‘ && ch <= ‘9‘){x = x * 10 + ch - ‘0‘;ch = getchar();} return x * f; } int n,p,k,m; short f[2][1003][53][53]; bool s[2][1003]; inline void R(short&x,short y){if(y>x)x=y;} int main() { memset(f,128,sizeof(f)); n=read();p=read();k=read(); m=read();for(int i=1;i<=m;i++) s[0][read()]=1; m=read();for(int i=1;i<=m;i++) s[1][read()]=1; if(p>=(n+k-1)/k*2) { int ans=0; for(int i=1;i<=n;i++) ans+=s[0][i]|s[1][i]; return 0*printf("%d\n",ans); } f[0][0][0][0]=0; for(int i=0,now=1,pre=0;i<n;i++,now^=1,pre^=1) { for(int j=0;j<=p;j++) { for(int x=0;x<=k;x++) for(int y=0;y<=k;y++) { if(!x&&!y) { R(f[now][j][0][0],f[pre][j][0][0]); R(f[now][j+1][0][k-1],f[pre][j][0][0]+s[1][i+1]); R(f[now][j+1][k-1][0],f[pre][j][0][0]+s[0][i+1]); R(f[now][j+2][k-1][k-1],f[pre][j][0][0]+(s[0][i+1]|s[1][i+1])); } else if(!x) { R(f[now][j][0][y-1],f[pre][j][0][y]+s[1][i+1]); R(f[now][j+1][k-1][y-1],f[pre][j][0][y]+(s[0][i+1]|s[1][i+1])); R(f[now][j+2][k-1][k-1],f[pre][j][0][y]+(s[0][i+1]|s[1][i+1])); } else if(!y) { R(f[now][j][x-1][0],f[pre][j][x][0]+s[0][i+1]); R(f[now][j+1][x-1][k-1],f[pre][j][x][0]+(s[0][i+1]|s[1][i+1])); R(f[now][j+2][k-1][k-1],f[pre][j][x][0]+(s[0][i+1]|s[1][i+1])); } else R(f[now][j][x-1][y-1],f[pre][j][x][y]+(s[1][i+1]|s[0][i+1])); f[pre][j][x][y]=-INF; } } } short ans=0; for(int x=0;x<k;x++) for(int y=0;y<k;y++) R(ans,f[n&1][p][x][y]); printf("%d\n",(int)ans); return 0; }
以上是关于Codeforces Round #408(div.2)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #408 (Div. 2) A
Codeforces Round #408 (Div. 2) B
Codeforces Round #408 (Div. 2)ABCD