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