题目名称:交换后的or
题意:给定两组长度为n的二进制串,请问有多少种方法在第一个串中交换两个不同位置上的数字,使得这两个二进制串“或”的结果发生改变?
输入:三行:第一行n表示串的长度,接下来两行为两个二进制串
输出:一行:方法数
输入示例:
5
01011
11001
输出示例:
4
示例提示:交换的位置(1,4),(2,3),(3,4),(3,5)
题意分析:
或运算规则:0|0=0,0|1=1,1|0=1,1|1=1,两个位中只要有一个1,结果为1,否则为0。
交换两个数字位置,能够使得最终结果改变,不难得出:交换的两个数字必须不同,也即只能0与1交换,否则交换没有意义。
以num(0)表示串中0的个数,以num(1)表示串中1的个数,那么可交换的方法有num(0)*num(1)种。
在第一个串改变之后,需要和第二个串进行或运算,因此并非所有num(0)*num(1)种方法都能满足最终结果的改变。
接下来分析不能改变最终结果的情况:
串一中交换的两个数字,在串二中对应的数字均为1。
由于或运算是:任一数字为1,结果为1。因此无论串一如何交换数字,其对应位置与串二进行或运算的结果都是1。
例如:
串一 : 10
串二 : 11
结果 : 11
改变串一数字位置以后:
串一 : 01
串二 : 11
结果 : 11
所以需要得知串二中数字1的个数n(遍历计数就可以得到)。
由于所做的操作是交换串一中任意两个不同数字,一次性交换两个,也就是一对,因此在得到串二中1的个数(n)后,需要求组合数C(n,2),串二的任意一对1,所对应到串一中的一对0和1的交换是无效的,不会改变最终结果。
然而,在C(n,2)种情况中,又存在这样的可能:串一中不曾交换的一对数,在串二中也对应着一对1。如果仅仅拿num(0)*num(1)减去C(n,2),则存在多减。
多减的情况有两种:
情况①:
串一 : 11
串二 : 11
两串对应数字均为1
情况②:
串一 : 00
串二 : 11
串一的数字0对应串二的数字1
将以上这两种情况中多减的数目加上,就是最终的方法数。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll fun(ll n){
ll result;
result=n*(n-1)/2;//C(n,2)公式化简后的结果
return result;
}
int main() {
char a[100010], b[100010];
ll n;
ll p1, p2, p3, p4;
cin>>n;
cin>>a>>b;
ll one_one_num=0, a_zero_num=0, b_one_num=0, zero_one_num=0;
for(ll i=0;i<n;i++){
if(a[i]=='0') a_zero_num++;//串一中0的个数
if(b[i]=='1') b_one_num++;//串二中1的个数
if(a[i]=='1' && b[i]=='1') one_one_num++;//两串中对应位都为1的个数
if(a[i]=='0' && b[i]=='1') zero_one_num++;//串一为0,且对应串二为1的个数
}
//串一中所有有效的交换方法数
p1=a_zero_num*(n-a_zero_num);
//求解C(n,2)
if(b_one_num==1) p2=0;
else if(b_one_num==2) p2=1;
else p2=fun(b_one_num);
//多减的情况一
if(one_one_num==1) p3=0;
else if(one_one_num==2) p3=1;
else p3=fun(one_one_num);
//多减的情况二
if(zero_one_num==1) p4=0;
else if(zero_one_num==2) p4=1;
else p4=fun(zero_one_num);
cout<<p1-p2+p3+p4;
return 0;
}
以上为赛时的AC代码,并非最优解,有不足欢迎指正交流。