Codeforces Global Round 18 A-C题解


A. Closing The Gap

题意:

\(n\)个整数\(a_1\)...\(a_n\),有一种操作:

选择两个a,b使a+=1,b-=1

问经过若干次操作后,\(Max(a_i...a_n)-Min(a_i...a_n)\)的最小值

思路:

想水流一样,这个高度差的最小值不可能>1(可自行证明)
如果\(\sum_{i=1}^n a_i\) \(mod\) \(n\)为0那么直接输出0
若不为0则输出1

代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
using namespace std;
#define int long long
int t,n,ans;
signed main(){
    cin>>t;
    while(t--){
        cin>>n;
        ans=0;
        for(int i=1;i<=n;++i){
            int a;
            cin>>a;
            ans+=a;
        }
        if(ans%n==0) puts("0");
        else puts("1");
    }
    return 0;
}

B. And It's Non-Zero

题意:

给定\(l\)\(r\),数列为\(l...r\),问至少删除多少个元素可以使按顺序进行与(&)运算的结果不为0

思路:

居然只要不为0就可以那我们只要确定\(l...r\)的数转换成二进制中,1最多的那一位,然后用数列中数的个数减去这一位的个数。例如:

l=1,r=4

那么转换成二进制就是:

4:1 0 0
3:0 1 1
2:0 1 0
1:0 0 1

定义记录一的数组为sum,则:

sum:1 2 2

输出结果为4-2=2
所以只管留最多1的位就是最优解。

代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
using namespace std;
int T,l,r;
int sum[200010][25];
int main(){
    // scanf("%d",&T);
    cin>>T;
    for(int i=1;i<=200000;++i){
        for(int j=1;j<=25;++j){
            sum[i][j]=sum[i-1][j];
        }
        int it=i;
        int jt=0;
        while(it){
            ++jt;
            sum[i][jt]+=(it%2);
            it/=2;
        }
    }
    while(T--){
        // scanf("%d%d",&l,&r);
        cin>>l>>r;
        int maxn=-1;
        for(int i=1;i<=25;++i){
            maxn=max(maxn,sum[r][i]-sum[l-1][i]);
        }
        // printf("%d\n",(r-l+1)-maxn);
        cout<<(r-l+1)-maxn<<endl;
    }
    return 0;
}

注意预处理的过程不要卡数组的线,要不然会导致一直乱输出
(昨天就因为这个调了半天)

C. Menorah

题意:

给两个长度为\(n\)的字符串a和b,给定一种操作:

固定a中一个‘1’,将其他字符反转(0变1,1变0)

问至少进行多少次操作可以使字符串a变成b。

思路:

我们不难发现,每进行两次操作我们其实都是交换了一对1和0

证明:
若第一次操作选择了第i位的1,那么第二次再选择第i位就是无意义的操作
第二次操作选择第j位的1,由于在第一次操作前第j位为0,也就是说,将操作后的第j位保留了下来,而其他反转
反转过后除了第i位都回归第一次操作前,而第i位变成了0
也就是说将一对1和0进行了交换

然后我们定义三个数组:

sumb为数组b中‘1’的个数,suma同理,dif为a和b有几位不同

\(sumb=suma\)我们可以直接从a交换到b,输出答案为dif
然后我们发现倒数第二个样例过不了(不得不说这次出的样例是真的良心),通过样例解释我们发现,可以将字符串a转换到除了第i位与b第i位都为1外其他任意一位都不相等(详情见cf),那么我们只需要固定第i位做一次操作即可,所以我们得出来下面一种可行的方案:

若n-suma==sumb-1(若成立则可以通过若干次操作后得到”字符串a转换到除了第i位与b第i位都为1外其他任意一位都不相等“这样一个串,然后固定一个1反转即可)
这种情况下答案就是(n-1)-dif+1
解释:第一个(n-1)-dif是指保留一位与b串相等的情况下把其他位都变为不等的操作次数,最后+1是最后的一次操作

代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
using namespace std;
const int inf=0x3f3f3f3f;
int T,n,suma,sumb,dif,ans;
string a,b;
int main(){
    // scanf("%d",&T);
    cin>>T;
    while(T--){
        // scanf("%d",&n);
        cin>>n;
        cin>>a>>b;
        ans=inf;
        suma = sumb = dif = 0;
        for(int i=0;i<n;++i){
            if(b[i]=='1') sumb++;
            if(a[i]=='1') suma++;
            if(a[i]!=b[i]) dif++;
        }
        if(suma==sumb){
            ans=min(ans,dif);
        }
        if(n-suma==sumb-1){
            ans=min(ans,n-dif);
        }
        if(ans==inf){
            puts("-1");
        }
        else printf("%d\n",ans);
    }
    return 0;
}
posted @ 2022-01-02 21:29  SZBR_yzh  阅读(45)  评论(0编辑  收藏  举报