返回顶部

Codeforces Round #664 (Div. 2)【ABCD】(题解)

涵盖知识点:思维、位运算、前缀和

比赛链接:传送门

A - Boboniu Likes to Color Balls

题意: 给定\(r,g,b,w\)四种颜色数量,每次操作可以选择\(r,g,b\)各一个然后变为三个\(w\),问最后这些颜色能否组成回文。
题解: 偶数次改变的奇偶性同第一次,所以只要判断两种情况。当且仅当奇数的数量为\(0,1\)时才有解。
Accept Code:

#include <bits/stdc++.h>
using namespace std;

int main(){
    int t;cin>>t;
    while(t--){
        int r,g,b,w;
        cin>>r>>g>>b>>w;
        int cnt=0;
        if(r&1)cnt++;
        if(g&1)cnt++;
        if(b&1)cnt++;
        if(w&1)cnt++;
        if(cnt<=1)puts("Yes");
        else{
            if(r==0||g==0||b==0)puts("No");
            else{
                r--,g--,b--,w+=3;
                int cnt=0;
                if(r&1)cnt++;
                if(g&1)cnt++;
                if(b&1)cnt++;
                if(w&1)cnt++;
                if(cnt<=1)puts("Yes");
                else puts("No");
            }
        }
    }
    return 0;
}

B - Boboniu Plays Chess

题意: 给定棋盘大小和一个非边缘的点,要求给出一种车走的方案遍历棋盘上的每个点。
题解: 先移到最左边缘,然后移到\((1,1)\)然后下上下上移动即可。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
bool vis[110][110];
int main(){
    int n,m,x,y;
    cin>>n>>m>>x>>y;
    cout<<x<<" "<<y<<"\n";
    cout<<x<<" 1\n1 1\n";
    vis[x][y]=vis[x][1]=vis[1][1]=true;
    int flag=1;
    x=y=1;
    for(int i=4;i<=m*n+2;i++){
        x+=flag;
        if(!vis[x][y])cout<<x<<" "<<y<<"\n";
        if(flag==1&&x==n)flag=-1,y++,x++;
        if(flag==-1&&x==1)flag=1,y++,x--;
    }
    return 0;
}

C - Boboniu and Bit Operations

题意: 给定两个长度分别为\(n,m\)的数组\(a,b\)。对于每一个\(1\le i\le n\)选择一个\(1\le j\le m\),令\(c_i=a_i \& b_j\)。求\(c_1|c_2|\ldots |c_{n-1}|c_{n}\)的最小值。
题解: 直接遍历\(2^9\)之内的所有答案。我们假设答案为\(x\),当且仅当对于所有的\(1\le i\le n\)都能找到一个\(1\le j \le m\)满足\((a_i\&b_j)|x=x\),这个答案就是合理的。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=210;
int a[maxn],b[maxn];
int main(){
    int n,m;
    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 x=0;x<=(1<<9);x++){
        for(int i=1;i<=n;i++){
            bool flag=false;
            for(int j=1;j<=m;j++){
                if(((a[i]&b[j])|x)==x){
                    flag=true;
                    break;
                }
            }
            if(!flag)goto st;
        }
        cout<<x<<"\n";
        return 0;
        st:;
    }
    return 0;
}

D - Boboniu Chats with Du

题意: Du在群里发出的值大于\(m\),就会被禁言\(d\)天。给定一个发言序列,要求重新排序,使得在\(n\)天内发出的值总和尽可能大,求最大值。
题解: 将所有的序列按照和\(m\)的大小分成两类后从大到小贪心排序。我们假设序列中大于\(m\)的值为\(a\),我们用\(x\)遍历\(0到a\),意思就是我们取大于\(m\)的天数为\(x\)天。那么算上禁言时间后就会花费\((x-1)(d+1)+1\)天,因为我们可以认为最后一天发言,然后禁言的影响不对最后答案产生负面效果。然后从小于等于\(m\)的贪心选择剩下的\(n-(x-1)(d+1)-1\)天。遍历所有可能取最大值即可。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
ll a[maxn],b[maxn];
int main(){
    int n,d,m,k=0,l=0;
    cin>>n>>d>>m;
    for(int i=1,x;i<=n;i++){
        cin>>x;
        if(x>m)a[++k]=x;
        else b[++l]=x;
    }
    if(k==0){
        ll ans=0;
        for(int i=1;i<=n;i++)ans+=b[i];
        cout<<ans<<"\n";
        return 0;
    }
    sort(a+1,a+k+1);
    reverse(a+1,a+k+1);
    for(int i=1;i<=k;i++)a[i]+=a[i-1];
    sort(b+1,b+l+1);
    reverse(b+1,b+l+1);
    for(int i=1;i<=n;i++)b[i]+=b[i-1];
    ll ans=0;
    for(int i=(k+d)/(d+1);i<=k;i++){
        if(1ll*(i-1)*(d+1)+1<=n)ans=max(ans,a[i]+b[n-1ll*(i-1)*(d+1)-1]);
    }
    cout<<ans<<"\n";
    return 0;
}
posted @ 2020-08-13 09:37  Charles1999  阅读(233)  评论(0编辑  收藏  举报