Codeforces Round #664 (Div. 2) 训练小结
Virtual participation
A. Boboniu Likes to Color Balls
分类讨论。
观察到能否组成回文与每种球的奇偶性有关,分类讨论即可,CF传统题型了。注意球数为0的情况。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
int R,G,B,W;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int T;cin>>T;
while(T--){
cin>>R>>G>>B>>W;
if((R+G+B+W)%2==0){
if(R%2==G%2&&R%2==B%2)puts("Yes");
else puts("No");
}
else{
if(W%2==1){
if(R%2==G%2&&R%2==B%2)puts("Yes");
else if(R!=0&&G!=0&&B!=0)puts("Yes");
else puts("No");
}
else puts("Yes");
}
}
return 0;
}
B. Boboniu Plays Chess
构造。
由于棋子类似于“車”,且路径上除了起点和终点的其他格子不算经过。所以可以构造方案:先走完当前行,然后跳到第一行,走完当前行再跳到第二行……以这个思路类推即可。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
int N,M,X,Y;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>N>>M>>X>>Y;
printf("%d %d\n",X,Y);
int i,j,tmp,pos;
for(j=1;j<=M;++j){
if(j==Y)continue;
printf("%d %d\n",X,j);
pos=j;
}
for(i=1,j;i<=N;++i){
if(i==X)continue;
printf("%d %d\n",i,pos);
for(j=1;j<=M;++j){
if(j==pos)continue;
printf("%d %d\n",i,j);
tmp=j;
}
pos=tmp;
}
return 0;
}
C. Boboniu and Bit Operations
暴力。
可能的答案数 \(< 2^{10}\),所以考虑从小到大枚举答案,判断答案是否成立。即若每一组 \(a[i]\) 和 \(b[j]\),均满足 \(ans|(a[i]\&b[j])=ans\),(相当于判断 \(ans\) 中是否某一位0/1无法取到),则该答案成立。判断复杂度 \(O(N^2)\),可以通过。
样例太臭了。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
int N,M,A[210],B[210];
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>N>>M;
for(int i=1;i<=N;++i)cin>>A[i];
for(int i=1;i<=M;++i)cin>>B[i];
for(int ans=0;ans<(1<<10);++ans){
int flag1=1,flag2;
for(int i=1;i<=N;++i){
flag2=0;
for(int j=1;j<=M;++j){
if((ans|(A[i]&B[j]))==ans){
flag2=1;
break;
}
}
if(!flag2){
flag1=0;
break;
}
}
if(flag1){printf("%d\n",ans);return 0;}
}
return 0;
}
D. Boboniu Chats with Du
《如何在禁言的边缘试探》
贪心题。
由于禁言天数 \(d\) 与元素值无关,所以当选择的元素数量确定时,选取的元素肯定越大越好。而会被禁言的和不会被禁言的元素计算方式不同,要分开考虑。
将a[]分成会被禁言的和不会被禁言的(是否大于 \(m\)),从大到小排序后取前缀和。
贪心的考虑如果选择了 \(x\) 个不大于 \(m\) 的元素,那么还能取 \(\left \lceil \frac{n-x}{d+1} \right \rceil\) 个 大于 \(m\) 的元素。枚举 \(x\) 贪心即可,注意 \(x\) 可以等于 0。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define dmax(_,__) ((_)>(__)?(_):(__))
using namespace std;
int N,D,M,A[100010];
long long ans,F[100010],G[100010];int cntF,cntG;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>N>>D>>M;
for(int i=1;i<=N;++i)
cin>>A[i];
sort(A+1,A+N+1);
for(int i=N;i>=1;--i)
if(A[i]>M){++cntG;G[cntG]=G[cntG-1]+A[i];}
else {++cntF;F[cntF]=F[cntF-1]+A[i];}
for(int i=0;i<=cntF;++i)
ans=dmax(ans,F[i]+G[(N-i+D)/(D+1)]);
printf("%lld\n",ans);
return 0;
}
E. Boboniu Walks on Graph
搜索+Hash。
对于每一组 \((c_i)\),原图可以转化为每个结点有且仅有一条出边的新图。
那就考虑对于 \(c_i=j\) 将出边的终点加入集合,确定一组 \((c_i)\) 时判断集合内是否包含 \(1\sim n\) 所有结点。hash即可。
赶时间写了单hash,过了。下次要尽量写双hash。
但有一个疑惑,如果新图是多个连通块,这个算法就是错误的。但训练时A了???不明白。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<vector>
#define dmax(_,__) ((_)>(__)?(_):(__))
using namespace std;
const long long mod=998244853;
int N,M,K;
long long ans,ha[200010],target,F[10][10];
vector<pair<int,int> > E[200010];
vector<int> deg[10];
void dfs(int d,long long now){
if(d>K){
ans+=(now==target);
return;
}
for(int i=0;i<d;++i)
dfs(d+1,(now+F[d][i])%mod);
return;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>N>>M>>K;
ha[0]=1;
for(int i=1;i<=N;++i){
ha[i]=ha[i-1]*1000000007ll%mod;
target=(target+ha[i])%mod;
}
for(int i=1,x,y,w;i<=M;++i){
cin>>x>>y>>w;
E[x].push_back(make_pair(w,y));
}
for(int i=1;i<=N;++i){
sort(E[i].begin(),E[i].end());
deg[E[i].size()].push_back(i);
}
for(int i=1;i<=K;++i)
for(int j=0;j<i;++j){
vector<int>::iterator it;
for(it=deg[i].begin();it!=deg[i].end();++it)
F[i][j]=(F[i][j]+ha[E[*it][j].second])%mod;
}
dfs(1,0);
printf("%lld\n",ans);
return 0;
}
不足
- D题开始读错题目,以为第 \(i\) 天是 \(a_i\),写了朴素贪心,过不了样例才发现读题出错。
- E题使用单hash,有出错的风险。

浙公网安备 33010602011771号