Codeforces Global Round 14(A-G)

感谢wxy_大佬给的E的思路

A

考场:n很小,随机化1e3次就好了。

正解:直接从1-n开始加,假如sum=x就交换 a[i] and a[i+1]

无解的情况就是 i=1na[i]=x

#include <bits/stdc++.h> #define N (int)(1e3+5) using namespace std; int a[N],n,m,t; int rd() { int f=1,sum=0; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();} return sum*f; } int main() { t=rd(); while(t--) { n=rd(); m=rd(); for(int i=1;i<=n;i++) a[i]=rd(); int fl=0; for(int i=1;i<=999;i++) { random_shuffle(a+1,a+1+n); int res=0,ok=1; for(int j=1;j<=n;j++) { res+=a[j]; if(res==m) ok=0; } if(ok) { puts("YES"); for(int j=1;j<=n;j++) printf("%d ",a[j]); puts(""); fl=1; break; } } if(!fl) puts("NO"); } return 0; }

B

手摸下可以发现一个单位正方形只能由2个/4个正方形组成,考虑除以2 or 4之后是否是完全平方数

#include <bits/stdc++.h> using namespace std; int t,n; int xx(int x) { return x*x; } int main() { cin>>t; while(t--) { cin>>n; if(n&1) puts("NO"); else { bool fl=0; for(int i=2;i<=n;i*=2) { if(n%i==0&&xx(sqrt(n/i))==n/i) fl=1; } if(fl) puts("YES"); else puts("NO"); } } return 0; }

C

考场:考虑2个的时候4个数 a b c d 升序

若这样选 ac bd

假设最优

a+c-b-d<a+d-b-c

得 a+b+2c<a+b+2d 显然成立

所以sort一遍 每m个一组 最后判断是否不超过x

别人的:优先队列找当前最小即可

#include <bits/stdc++.h> #define N (int)(1e5+5) using namespace std; struct node { int x,id; }a[N]; int b[N],be[N],n,m,k,t; bool cmp(node x,node y) { return x.x<y.x; } int rd() { int f=1,sum=0; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();} return sum*f; } int main() { t=rd(); while(t--) { memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(be,0,sizeof(be)); n=rd(); m=rd(); k=rd(); for(int i=1;i<=n;i++) a[i].x=rd(),a[i].id=i; sort(a+1,a+1+n,cmp); int las=0,tot=0; for(int i=1;i<=n;i++) { int id=(i-1)/m+1; if(las!=id) las=id,tot=0; b[++tot]+=a[i].x; be[a[i].id]=tot; } int mx=0,mi=0x7fffffff; for(int i=1;i<=m;i++) mx=max(mx,b[i]),mi=min(mi,b[i]); //cout<<mx<<" "<<mi<<endl; if(mx-mi>k) { puts("NO"); continue; } puts("YES"); for(int i=1;i<=n;i++) printf("%d ",be[i]); puts(""); } }

D

考虑l=r的情况,我们可以发现,ans=[1,l]在[l+1,r]没出现的个数。

考虑类比到l<r,最优策略应该是先统计有出现的,再将[l+1,n]中出现次数大于1的给到[1,l]总共给cnt/2个。

l>r同理

#include <bits/stdc++.h> #define N (int)(2e5+5) using namespace std; bool vis[N]; int c[N],a[N],n,l,r,t; int rd() { int f=1,sum=0; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();} return sum*f; } int main() { t=rd(); while(t--) { memset(a,0,sizeof(a)); memset(c,0,sizeof(c)); n=rd(); l=rd(); r=rd(); for(int i=1;i<=n;i++) a[i]=rd(); if(l==r) { int res=0; for(int i=1;i<=l;i++) ++c[a[i]]; for(int i=l+1;i<=n;i++) if(!c[a[i]]) ++res; else --c[a[i]]; printf("%d\n",res); } else if(l<r) { // sort(a+1,a+l+1); sort(a+l+2,a+n+1); int le=(r-l)/2,res=0,mx=0; for(int i=l+1;i<=n;i++) ++c[a[i]],mx=max(mx,a[i]); //for(int i=l+1;i<=n;i++) vis[a[i]]=1; for(int i=1;i<=l;i++) if(!c[a[i]]) ++res; else --c[a[i]]; for(int i=1;i<=mx;i++) { if(le<=0) break; if(c[i]>1) { if(c[i]/2>le) res+=le; else res+=c[i]/2; le-=c[i]/2; } } if(le>0) res+=le*2; printf("%d\n",res); } else { int le=(l-r)/2,res=0,mx=0; for(int i=1;i<=l;i++) ++c[a[i]],mx=max(mx,a[i]); for(int i=l+1;i<=n;i++) if(!c[a[i]]) ++res; else --c[a[i]]; for(int i=1;i<=mx;i++) { if(le<=0) break; if(c[i]>1) { if(c[i]/2>le) res+=le; else res+=c[i]/2; le-=c[i]/2; } } if(le>0) res+=le*2; printf("%d\n",res); } } }

E

考虑令开机的为1不开机的为0,那么一定不存在连续超过2个0,且每段1之间必定只有1个0间隔。

由于n只有400,考虑dp。

设f[i][j]为到i时分j段1的方案数。

初始化即 f[1][1]=1 f[i][1]=f[i-1][1]*2。

即设前面那段为a,后面单独的为b,有2种方案: ab/ba。

先枚举i,之后枚举j表示当前分几段,后面枚举k,表示第j+1段的len。

f[i+k+1][j+1]=(f[i+k+1][j+1]+f[i][j]C[i+k+1j][k]

首先 i+k+1代表着当前的长度(原来为i,这一段为k,间隔的0为1)

$ f[i][j]C[i+k+1-j][k]p[k-1]$ 代表 到i分j段的方案数乘上当前所有的1(因为j+1段,所以j个间隔0)选出k个来作为新段的组合方案再乘上k个1任意排列的方案数。

#include <bits/stdc++.h> #define N 405 #define int long long using namespace std; int f[N][N],C[N][N],p[N],mod,n; signed main() { cin>>n>>mod; f[1][1]=p[0]=1; for(int i=2;i<=n;i++) f[i][1]=(f[i-1][1]*2)%mod; for(int i=1;i<=n;i++) p[i]=(p[i-1]*2)%mod; for(int i=0;i<N;i++) { C[i][0]=1; for(int j=1;j<=i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod; } for(int i=1;i<=n;i++) { for(int j=1;j<=i;j++) { for(int k=1;i+k+1<=n;k++) { f[i+k+1][j+1]=(f[i+k+1][j+1]+f[i][j]*C[i+k+1-j][k]%mod*p[k-1]%mod)%mod; } } } int answ=0; for(int i=0;i<=n;i++) answ=(answ+f[n][i])%mod; cout<<answ; return 0; }

F

首先, (n1)x>sum 肯定不行,因为不会凭空产生。
反之,必定可以,因为总会有一种排列使得所有的前缀和都大于x*i。

我们考虑这是在树上的,当前节点为x,子节点为y。

我们可以发现,应该先考虑叶子节点,再从底层转移到上层,所以先dfs(y)。

考虑 val[x]+val[y]>=x ,于是我们直接顺序记录进去,并更新 val[x]=val[x]+val[y]x

否则,我们应该从x去修到y,倒序记录这条边,因为要修好x及其以上的节点才能推到y。

关于路径记录考虑开个双端队列即可。

#include <bits/stdc++.h> #define N (int)(3e5+5) #define int long long using namespace std; struct edge{ int nex,to,id; }e[N<<1]; bool vis[N]; int ans[N],ct1,ct2,head[N],cnt; int n,m,v,a[N]; void dfs(int x,int fa) { if(vis[x]) return; vis[x]=1; for(int i=head[x];i;i=e[i].nex) { int y=e[i].to; if(y==fa||vis[y]) continue; dfs(y,x); if(a[x]+a[y]>=v) { a[x]=a[x]+a[y]-v; ans[ct1++]=e[i].id; } else { ans[--ct2]=e[i].id; } } } void add(int x,int y,int z) { e[++cnt]=edge{head[x],y,z}; head[x]=cnt; } signed main() { cin>>n>>m>>v; int sum=0; for(int i=1;i<=n;i++) { cin>>a[i]; sum+=a[i]; } if(sum<(n-1)*v) { puts("NO"); return 0; } int x,y; for(int i=1;i<=m;i++) { cin>>x>>y; add(x,y,i); add(y,x,i); } // for(int i=1;i<=n;i++) add(0,i,-1); //g.push_back(1); ct2=n-1; dfs(1,0); puts("YES"); for(int i=0;i<n-1;i++) cout<<ans[i]<<endl; return 0; }

G

题解

#include <bits/stdc++.h> #define N (int)(2e5+5) #define int long long using namespace std; struct edge { int st,nex,to,w; }e[N<<1]; int head[N],vis[N],cnt,low[N],dfn[N],tot,col,id[N],val[N],flag[N],dep[N],gc[N]; int n,m,t; int rd() { int f=1,sum=0; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();} return sum*f; } void add(int x,int y,int z) { e[++cnt]=edge{x,head[x],y,z}; head[x]=cnt; } int gcd(int x,int y) { return y==0?x:gcd(y,x%y); } stack<int>s; void tarjan(int x) { dfn[x]=low[x]=++tot; flag[x]=1; s.push(x); for(int i=head[x];i;i=e[i].nex) { int y=e[i].to; if(!dfn[y]) { dep[y]=dep[x]+e[i].w; tarjan(y); low[x]=min(low[x],low[y]); } else if(flag[y]) { low[x]=min(low[x],dfn[y]); gc[x]=gcd(gc[x],dep[x]+e[i].w-dep[y]); } } if(low[x]==dfn[x]) { int qwq=0; ++col; do { qwq=s.top(); s.pop(); id[qwq]=col; flag[qwq]=0; } while(qwq!=x); } } signed main() { n=rd(); m=rd(); int x,y,z; for(int i=1;i<=m;i++) { x=rd(); y=rd(); z=rd(); add(x,y,z); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); for(int i=1;i<=n;i++) val[id[i]]=gcd(val[id[i]],gc[i]); t=rd(); while(t--) { x=rd(); y=rd(); z=rd(); //cout<<y<<" "<<val[id[x]]<<" "<<z<<endl; if(!id[x]) puts("NO"); else if(y%gcd(val[id[x]],z)==0) puts("YES"); else puts("NO"); } return 0; }

__EOF__

本文作者F x o r G
本文链接https://www.cnblogs.com/xugangfan/p/15872252.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   FxorG  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示