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;
}

不足

  1. D题开始读错题目,以为第 \(i\) 天是 \(a_i\),写了朴素贪心,过不了样例才发现读题出错。
  2. E题使用单hash,有出错的风险。
posted @ 2020-09-30 18:35  Dayu2001  阅读(124)  评论(0)    收藏  举报