套题 codeforces 360
A题:Opponents
直接模拟
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; char ch[200]; int main() { int n,k; while(~scanf("%d%d",&n,&k)) { int p=0,sta=1,first=1,ans; for(int i=0;i<k;i++) { sta=1; scanf("%s",ch); for(int i=0;i<n;i++) sta&=(ch[i]-'0'); if(sta==0) p++; if(sta==1||(i==k-1)) { if(first) {ans=p;first=0;} else { ans=max(ans,p); } p=0; } } printf("%d\n",ans); } return 0; }
B题: Lovely Palindromes
偶数长度的回文串
可以把这个回文串当做两半来处理,对于任何一个数字,只要把它反转后加到
数字尾,就可以形成一个回文串,且符合偶数长度的条件
既然任何数字都可以,那么第n个数就是以n来构造的
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; const int Max=1e5+10; char ch[Max]; int main() { while(~scanf("%s",ch)) { printf("%s",ch); reverse(ch,ch+strlen(ch)); printf("%s\n",ch); } return 0; }
C题:NP-Hard Problem
要求将一张图分成两个顶点集合,每个集合包含所有的边
要使得这样的集合成立,必须把每一条边上的两点分别分到两个集合中去
可以利用并查集分点,一个集合祖先节点小于等于n(小于等于(因为n+n))
另一个祖先节点大于n。
这两个集合有没有交集取决于同一条边上的两个顶点不能在同一集合
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; const int Max=1e5+10; int fa[Max*2]; int find(int x) { return fa[x]==-1?x:fa[x]=find(fa[x]); } void Union(int x,int y) { int f1=find(x),f2=find(y); if(f1!=f2) fa[f1]=f2; } vector<int>ans1,ans2; int vis[Max]; int main() { int n,m; while(~scanf("%d%d",&n,&m)) { memset(fa,-1,sizeof(fa)); memset(vis,0,sizeof(vis)); int u,v,flag=0; for(int i=1;i<=m;i++) { scanf("%d%d",&u,&v); if(find(u)==find(v)) flag=1; //两个顶点已经在同一集合,无解 Union(u,v+n); Union(u+n,v); vis[u]=vis[v]=1; } ans1.clear();ans2.clear(); for(int i=1;i<=n;i++) { if(!vis[i]) continue; if(find(i)<=n) ans1.push_back(i); else ans2.push_back(i); } if(ans1.empty()||ans2.empty()||flag) puts("-1"); else { if(ans1.size()>ans2.size()) swap(ans1,ans2); printf("%d\n",ans1.size()); for(int i=0;i<ans1.size();i++) { if(i) printf(" "); printf("%d",ans1[i]); } printf("\n%d\n",ans2.size()); for(int i=0;i<ans2.size();i++) { if(i) printf(" "); printf("%d",ans2[i]); } puts(""); } } return 0; }
同样地,既然已经知道了解这道题的关键就是让每一条边的两个点分散到
两个不同的集合里面,那么直接dfs进行染色也是一个简洁易写的方法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; const int Max=1e5+10; vector<int>G[Max]; vector<int>ans1,ans2; int vis[Max],col[Max]; bool dfs(int u,int c,int pre) { col[u]=c; int v; for(int i=0;i<G[u].size();i++) { v=G[u][i]; if(v==pre) continue; if(col[v]==c) return 0; if(col[v]!=-1) continue; if(!dfs(v,!c,u)) return 0; } return 1; } int main() { int n,m; while(~scanf("%d%d",&n,&m)) { memset(vis,0,sizeof(vis)); memset(col,-1,sizeof(col)); int u,v; for(int i=1;i<=m;i++) { scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); vis[u]=vis[v]=1; } int root,flag=0; for(int i=1;i<=n;i++) if(vis[i]) { root=i; if(col[root]!=-1) continue; if(!dfs(root,1,0)) flag=1; } if(flag) puts("-1"); else { ans1.clear();ans2.clear(); for(int i=1;i<=n;i++) { if(col[i]==1) ans1.push_back(i); if(col[i]==0) ans2.push_back(i); } if(ans1.size()>ans2.size()) swap(ans1,ans2); printf("%d\n",ans1.size()); for(int i=0;i<ans1.size();i++) { if(i) printf(" "); printf("%d",ans1[i]); } printf("\n%d\n",ans2.size()); for(int i=0;i<ans2.size();i++) { if(i) printf(" "); printf("%d",ans2[i]); } puts(""); } } return 0; }
D题:Remainders Game
已知:
x mod c1 = m1
x mod c2 = m2
......
x mod cn = mn
这里要求知道x mod (k)的值,那么就要求lcm(c1,c2,c3,.....,cn)==k,并且ci之间互质
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> #define scan(x,y) scanf("%d%d",&x,&y) using namespace std; typedef long long LL; const int Max=1e5+10; int n,m; LL gcd(LL a,LL b) { return b==0?a:gcd(b,a%b); } int main() { scan(n,m); LL ans=1; int x; for(int i=1;i<=n;i++) { scanf("%d",&x); ans=gcd((LL)m,ans*(LL)x/gcd(ans,x)); } if(ans==(LL)m) cout<<"Yes"<<endl; else cout<<"No"<<endl; return 0; }
E题:The Values You Can Make
有n个价值不一的硬币,问能够凑出的所有面值(<=m)
dp[i][j],意为已经拥有j面值的情况下,能否凑成j面值
1.dp[0][0]=1
2.if(dp[l-x][j]) dp[l][j]=1 and dp[l][j+x]=1;
3.已拥有的硬币转移方向应该从大到小,因为用一枚硬币不能使用多次,不能对后面的
数值持续影响
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; const int Max=500+10; short dp[Max][Max]; vector<int>ans; int main() { int n,k; while(~scanf("%d%d",&n,&k)) { memset(dp,0,sizeof(dp)); dp[0][0]=1; int x; for(int i=0;i<n;i++) { scanf("%d",&x); for(int l=k;l>=x;l--) { for(int r=0;r<=k-x;r++) { if(dp[l-x][r]) dp[l][r]=dp[l][r+x]=1; } } } ans.clear(); for(int i=0;i<=k;i++) { if(dp[k][i]) ans.push_back(i); } printf("%d\n",ans.size()); for(int i=0;i<ans.size();i++) { if(i) printf(" "); printf("%d",ans[i]); } puts(""); } return 0; }