Codeforces Round #360 (Div. 2) C D E
Posted 天翎月
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #360 (Div. 2) C D E相关的知识,希望对你有一定的参考价值。
每次AB秒出 到了C难度陡然上升...翻译都弄不懂...
C 给出一张图 找出两个点的覆盖集(覆盖集是指这图中每条边都有至少一个点在这个点集里面) 并且两个点集没有交集 英文很难看懂...就是二分图的判定 看看这张图是不是二分图 输出两边的点 不是二分图输出-1
坑点是这是special judge 但是题目没说 每个联通块都要进行一次bfs 那些独立点可以不输出也可以随意分配
D 给出k与n个数ci 我们知道一个未知的数x%ci的数 问能不能求出x%k的数
可以利用中国剩余定理来解
如果我们知道 x=A mod c1 = B mod c2 可以求出x的通解 x= lcm(c1,c2)q+z 这里的q是一个倍数
那么当lcm(c1,c2...)是k的倍数的时候 满足 所有的 kq都有lcm()q来对应 所以这时候一定可以通过z求出x%k
所以只需要求一下ci之间的lcm就好啦 最后看lcm是不是k的倍数
但是 直接求lcm会超int什么的
可以每次都让lcm%=k 一旦lcm为k的倍数的时候就永远为0下去了
E A有n个硬币 B有k价值的东西 A从这些硬币中找出一些使和等于k和B交换 A想知道B能利用这些硬币摆出多少的状态 都输出
设置dp[i][j] i表示A拿出的硬币的总和 j表示从这些硬币中拿出来的部分的总和 1 为存在 0 为不存在
初始dp[0][0]=1
关于代码内dp方程的转移:首先枚举硬币的种类 再枚举i 需要注意的是i要从大往小去枚举 这和背包中01和完全的区别类似 当我们从上向下枚举的时候 就不会出现同一种东西加成在小东西上 又在小东西升级的大东西上再次作用这种状况了 问题中硬币是只有一个的 所以是01 从上向下枚举 而当面对完全背包的情况下 我们可以无限制的加入东西 所以应该从小往下枚举 枚举j的时候只需要从0向k枚举就好 因为之后还会进行判断 dp[i][j]==1 这时候就说明这种状态是存在的 然后我们对dp[i+c][j]和dp[i+c][j+c]进行操作 可以看出 由于枚举硬币的顺序 每个状态的i和j都只能被放进去一种硬币
初始化的时候只做dp[0][0]就好 其余的让它自己去推...
C
#include<stdio.h> #include<string.h> #include<algorithm> #include<map> #include<math.h> #include<iostream> #include<queue> using namespace std; int n,m; int point[100050]; struct node { int v; int nex; }; node b[200050]; int cnt; void add(int u,int v) { b[cnt].v=v; b[cnt].nex=point[u]; point[u]=cnt; cnt++; } int co[100050]; bool bfs(int z) { queue<int >q; q.push(z); co[z]=1; while(!q.empty()) { int f=q.front(); q.pop(); for(int tt=point[f]; tt!=-1; tt=b[tt].nex) { int v=b[tt].v; if(co[v]==0) { if(co[f]==1) { co[v]=2; q.push(v); } else { co[v]=1; q.push(v); } } else if(co[v]==co[f]) { return false; } else { continue; } } } return true; } int main() { cin>>n>>m; cnt=0; for(int i=1; i<=n; i++) { point[i]=-1; co[i]=0; } for(int i=1; i<=m; i++) { int u,v; cin>>u>>v; add(u,v); add(v,u); } bool ans=true; for(int i=1;i<=n;i++){ if(co[i]==0){ ans=bfs(i); if(ans==false){ printf("-1\n"); break; } } } if(ans==true){ int res=0; for(int i=1; i<=n; i++) { if(co[i]==1) { res++; } } printf("%d\n",res); int c=0; for(int i=1; i<=n; i++) { if(co[i]==1) { printf("%d",i); c++; if(c==res) printf("\n"); else printf(" "); } } c=0; res=0; for(int i=1; i<=n; i++) { if(co[i]!=1) { res++; } } printf("%d\n",res); for(int i=1; i<=n; i++) { if(co[i]!=1) { printf("%d",i); c++; if(c==res) printf("\n"); else printf(" "); } } } }
D
#include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> #include<map> #include<iostream> using namespace std; long long k; int n; long long gcd(long long a,long long b) { if(b==0) return a; return gcd(b,a%b); } long long lcm(long long a, long long b) { return a*b/gcd(a,b); } int main() { scanf("%d%lld",&n,&k); long long cc; scanf("%lld",&cc); long long gbs=cc; bool ans=false; if(k==1) { ans=true; } if(n==1) { if(cc%k==0) ans=true; } for(int i=2; i<=n; i++) { scanf("%lld",&cc); if(ans==true) continue; gbs=lcm(cc,gbs); gbs%=k; if(gbs==0) { ans=true; } } if(ans==true) { printf("Yes\n"); } else printf("No\n"); }
E
#include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> #include<map> using namespace std; int n,k; int c[505]; int dp[500][500]; int main() { scanf("%d%d",&n,&k); for(int i=1; i<=n; i++) scanf("%d",&c[i]); memset(dp,0,sizeof(dp)); /*for(int i=1; i<=n; i++) { dp[c[i]][c[i]]=dp[c[i]][0]=1; }*/ dp[0][0]=1; for(int i=1; i<=n; i++) { for(int j=k-c[i]; j>=0; j--) { for(int o=0; o<=k; o++) { if(dp[j][o]==1) { dp[j+c[i]][o]=1; if(o+c[i]<=k) { dp[j+c[i]][o+c[i]]=1; } } } } } int ans=0; for(int i=0; i<=k; i++) { if(dp[k][i]==1) { ans++; } } printf("%d\n",ans); int s=0; for(int i=0; i<=k; i++) { if(dp[k][i]==1) { { printf("%d",i); s++; if(s==ans) printf("\n"); else printf(" "); } } } }
拖了两天才补完的cf..补题的感觉真是亦可赛艇...
以上是关于Codeforces Round #360 (Div. 2) C D E的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #360 (Div. 2) D 数学推导 E dp
Codeforces Round #360 (Div. 1) D. Dividing Kingdom II 并查集求奇偶元环