Codeforces Round #794 (Div. 2)(A-D)题解

A. Everything Everywhere All But One

题目链接:Problem - A - Codeforces

题意:给出n个数,每一次操作可以选择n-1个数,将它们代替为它们的算术平均值(分数也可以),问任意次操作后是否可以使得全部数相等。

思路:如果选择的这n-1个数的算数平均值为分数,那么不管操作多少次都不可能使得全部数相等,因为另外一个数为整数。对全部数求和,然后遍历1-n,每次选择除了第i个数的另外n-1个数判断是否整除(n-1)且商等于a[i]即可。

AC code:

#include <bits/stdc++.h>

using namespace std;
int n,a[60]; 
void solve(){
    cin>>n;
        long long sum=0;
        for(int i=1;i<=n;i++){
            cin>>a[i];
            sum+=a[i];
        }
//        cout<<sum<<endl;
        for(int i=1;i<=n;i++){
            int t=sum-a[i];
//            cout<<t<<' ';
            if((t%(n-1))==0){
                int tt=t/(n-1);
                if(tt==a[i]){
                    cout<<"YES"<<endl;
                    return ;
                }
            }
        }
        cout<<"NO"<<endl;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
} 

B. Odd Subarrays

题目链接:Problem - B - Codeforces

题意:给出n个数,问怎样切分这n个数,使得尽可能多的子数组中逆序对数为奇数。

思路:要使子数组尽可能的多且子数组中逆序对数为奇数,则就选相邻的逆序对为一个子数组即可,遍历一遍判断一下即可。注意:是切分,不能重复。

AC code:

#include <bits/stdc++.h>

using namespace std;
int n,a[100010];
int main(){
    int t;
    cin>>t;
    while(t--){
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        int cnt=0;
        for(int i=1;i<n;i++){
            if(a[i]>a[i+1]){
                cnt++;
                i++;
            }
        }
        cout<<cnt<<endl;
    }
    return 0;
} 

C. Circular Local MiniMax

题目链接:Problem - C - Codeforces

题意:n个数形成一个环,对这n个数进行排列,问是否存在一种情况使得每个数要么同时比它相邻的数大,要么同时比它相邻的数小。

思路:可以按照一小一大进行排列,那么n为奇数时一定不能满足题意,n为偶数时,对n个数进行排序,然后一小一大放置,最后遍历一遍检验是否满足同时大或者同时小。

AC code:

#include <bits/stdc++.h>

using namespace std;
int n,a[100010],b[100010];
void solve(){
            cin>>n;
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        if(n&1){
            cout<<"NO"<<endl;
            return ;
        }
        sort(a+1,a+n+1);
        for(int i=0;i<=n+1;i++) b[i]=0;
        b[0]=a[n],b[n+1]=a[1];
        int j=1;
        for(int i=1;i<=n;i+=2){
            b[i]=a[j];
            j++;
        }
        j=n/2+1;
        for(int i=2;i<=n;i+=2){
            b[i]=a[j];
            j++;
        }
//        cout<<endl;
//        for(int i=1;i<=n;i++) cout<<b[i]<<' ';
//        cout<<endl;
        for(int i=1;i<=n;i++){
            if(b[i]==b[i-1] || b[i]==b[i+1]){
                cout<<"NO"<<endl;
                return ;
            }
        }
        cout<<"YES"<<endl;
        for(int i=1;i<=n;i++) cout<<b[i]<<' ';
        cout<<endl;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
} 

D. Linguistics

题目链接:Problem - D - Codeforces

题意:告诉你‘A’,‘B’,‘AB’,‘BA’的数量,并且给出一个字符串仅含有‘A’和‘B’,判断用给出的元素是否能组成该字符串。

思路:学习的大佬的思路:Codeforces Round #794 (Div. 2 + Div. 1) A-D - 知乎 (zhihu.com),大概就是求出组成该字符串所需的最小的‘A’,‘B’,‘AB’,‘BA’数量,然后判断是否满足给出的数量。首先判断是否‘A’的数量等不等于a+c+d,不相等一定不满足题意。

然后去找类似连续的不相等子串,例如:ABABA,BABA....当子串长度为偶数时,且单‘A’和单‘B’没有剩余时,那么对‘AB’或者‘BA’的贡献数量就是len/2,如果有单‘A’和单‘B’剩余,则可以将头尾与该子串断开,若原来是ABABAB,则断开后就为BABA了,那么断开后的子串对‘AB’就不再有贡献了。

BA开头的偶数子串同理。当子串长度为奇数时,可以切除头或者尾从而得到偶数子串,并且对单‘A’或者单‘B’的贡献为1。最后从长的偶数子串开始断开,这样能保证最后求出的是最少数量。

AC code:

#include <bits/stdc++.h>

using namespace std;
int a,b,c,d,cnt[200010];
char s[200010];
void solve(){
    cin>>a>>b>>c>>d;
    cin>>s+1;
    int n=strlen(s+1);
    int num=count(s+1,s+n+1,'A');
    if(num!=a+c+d){
        cout<<"NO"<<endl;
        return ;
    }
    vector<int> ab,ba;
    int cntab=0,cntba=0;
    for(int i=1;i<=n;i++){
        int j=i;
        while(j+1<=n && s[j]!=s[j+1]) j++;
        if(j-i+1&1){
            if(s[i]=='A'){
                a--;
            }else{
                b--;
            }
        }else{
            if(s[i]=='A'){
                cntab+=((j-i+1)>>1);
                ab.push_back(((j-i+1)>>1));
            }else{
                cntba+=((j-i+1)>>1);
                ba.push_back((j-i+1)>>1);
            }
        }
        i=j;
    }
    if(a<0 || b<0){
        cout<<"NO"<<endl;
        return ;
    }
    {
        int t=min(a,b);
        sort(ab.begin(),ab.end());
        while(!ab.empty() && t){
            t--;
            cntab-=ab.back();
            ab.pop_back();
        }
        if(cntab>c){
            cout<<"NO"<<endl;
            return ;
        }
    }
    {
        int t=min(a,b);
        sort(ba.begin(),ba.end());
        while(!ba.empty() && t){
            t--;
            cntba-=ba.back();
            ba.pop_back();
        }
        if(cntba>d){
            cout<<"NO"<<endl;
            return ;
        }
    }
    cout<<"YES"<<endl;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
} 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值