题目描述
叶姐要想哥赠送一串比特手链,这个手链由0和1组成。想哥买了手链B,无意间得知叶姐想要同样长度的手链A。想哥囊中羞涩,只能手工调整手链。他希望最少通过以下操作进行最少步骤把B变成A。注意:A != B
对于一个串S:
操作1——选择下标i,j,i != j:
·result = S[i] & S[j]
·S[i] = result & S[i]
·S[j] = result & S[j]
操作2——选择下标i,j,i != j:
·result = S[i] | S[j]
·S[i] = result | S[i]
·S[j] = result | S[j]
操作3——选择下标i,j,i != j:
·result = S[i] ^ S[j]
·S[i] = result ^ S[i]
·S[j] = result ^ S[j]
问想哥最少多少步能达成心愿。如果想哥无法达成心愿,输出-1。
输入
第一个数为数据组数T
接下来2T行,第2i - 1行为手链B,第2i行为手链A
输出
对于每组数据,输出一行,最少的步骤数。特别地,如果无法达成,输出-1。
输入样例
2
101
010
1111
1010
输出样例
2
-1
Hint
T<=5;
长度<=10^6;
思路
碰到这种类型,一般都要先手动模拟,寻找规律。
通过手动计算可以发现,若a[i] == a[j],则三个运算均不会造成影响;只有a[i] != a[j]时,即一个为0一个为1,才会造成改变。
对于&:相当与把1变成0;对于|:相当于把0变成1;对于^,相当于交换。
所以,如果原串全为0或全为1,由于A!=B,所以是无解的;否则解的个数即为max(0变成1的数量,1变成0的数量),也就是说,尽量使用^交换一次性解决两个,无法交换了再用&或|一次修改一个。
参考代码
1 //我的版本 2 #include<stdio.h> 3 #include<string.h> 4 #define MAXN 1000002 5 int main() 6 { 7 int T;//数据组数 8 scanf("%d",&T); 9 while(T--){ 10 char b[MAXN],a[MAXN]; 11 scanf("%s%s",b,a); 12 int i,ans_b0 = 0; 13 int len = strlen(b); 14 int t01 = 0,t10 = 0; 15 for(i = 0;i < len;i++){ 16 if(b[i] == '0') 17 ans_b0++; 18 if(b[i] == '0' && a[i] == '1') 19 t01++; 20 if(b[i] == '1' && a[i] == '0') 21 t10++; 22 } 23 if(ans_b0 == len || ans_b0 == 0){ 24 printf("-1\n"); 25 continue; 26 } 27 printf("%d\n",Max(t01,t10)); 28 } 29 30 return 0; 31 } 32 33 int Max(int a,int b) 34 { 35 return a > b ? a : b; 36 }
1 //助教的版本 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 6 const int N=1000010; 7 int len,l,r,t,sum; 8 char a[N],b[N]; 9 10 inline int max(int a,int b) { 11 return a>b?a:b; 12 } 13 14 int main() { 15 for(scanf("%d",&t);t--;l=r=sum=0) { 16 scanf("%s%s",a,b); 17 len=std::strlen(a); 18 for(int i=0;i<len;++i) sum+=a[i]-'0'; 19 if(sum==0 || sum==len) { 20 puts("-1"); 21 continue; 22 } 23 for(int i=0;i<len;++i) 24 if(a[i]!=b[i]) 25 a[i]=='0' ? ++l : ++r; 26 printf("%d\n",max(l,r)); 27 } 28 return 0; 29 }