Codeforces Global Round 18 C. Menorah
最近期末周,补个C复习期末去了,写一下我对这题的理解和证明。只看代码的话还是满简单的,没有题目经验所以推出这道题对我来说还是满困难的。
思路+证明: 一共有$4$个状态:$00、01、10、11。$根据题目的意思,首先至少有一支点燃的蜡烛才能进行操作,并且每次操作点燃的蜡烛状态不改变,其他状态如果是$0$变成$1$否则变成$0$。那我们开始考虑 $string$ $A$ 如何变成$string$ $B$。首先有$1$个性质,$1$个数操作最多不超过$1$次,因为如果操作$2$次和没操作是一样的,而我们求的是最小操作次数。那么$11$和$00$最后要想保持不变,那么被改变的次数一定是偶数次,而如果$01$和$10$最后肯定是要变成$00$和$11(题目要求)$那么肯定要被改变奇数次。那这时候题目就转变成了如何让$11、00$改变偶数次,$10、01$改变奇数次。 因为上面说过一个点燃的蜡烛操作的时候自身是不会改变的,那么我们可以通过2次操作使得一组$01、10$变成$11、00$,例如:
$10$ $11$ $01$
$01$ $01$ $01$
我们可以发现,要想通过操作$01、10$最终让$string$ $A$ 变成$string$ $B$那么上面的$1$的个数和下面的$1$的个数一定要相等,才能通过移动上面$1$的位置使得上面和下面是一样的,换句话说就是$01$的数量和$10$的数量要相等。否则如果$01$和$10$数量不相等那我们还可以判断是否其满足第二种条件,是否能够通过被动改变奇数次使得上面变成下面,那么也就是$11、00$部分操作奇数次被动改变$01、10$部分。那么最终$11、00$部分需要改变偶数次,所以每个$11、00$部分都要操作一次。并且$11$的数量+$00$的数量一定是奇数个而且要满足$11$部分一次操作后其余的$11、00$部分变成$10、01$数量相等,这前提需要满足一种性质:$11$的数量-$00$的数量为$1$,然后就转变成第一种情况。如果都不满足那么输出$-1$(真的很难白话讲清这东西)
- 参考代码:
#include<bits/stdc++.h>
using namespace std;
#define mp make_pair
#define int long long
#define re register int
#define pb emplace_back
#define lowbit(x) (x&-x)
#define fer(i,a,b) for(re i = a ; i <= b ; i ++)
#define der(i,a,b) for(re i = a ; i >= b ; i --)
#define snow ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int lcm(int a,int b){return a*b/gcd(a,b);}
typedef pair<int,int>PII;
typedef pair<int,string>PIS;
string s1,s2;
int a,b,c,d;
int val;
signed main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
cin>>s1>>s2;
a=b=c=d=0;
for(int i=0;i<s1.size();i++){
if(s1[i]=='0'){
if(s2[i]=='0')a++;
else b++;
}
else{
if(s2[i]=='0')c++;
else d++;
}
}
if(s1==s2){
cout<<0<<endl;
continue;
}
val=INT_MAX;
if(b==c){
val=min(val,b+c);
}
if(d-a==1){
val=min(val,d+a);
}
cout<<(val==INT_MAX?-1:val)<<endl;
}
return 0;
}
Orz