案例七:异或数列

分析:

初始时,Alice和Bob分别有一个整数a和b,均为0。注意,0⊕Xi=Xi。所以,初值0对选择的数没有影响
我们设在游戏结束后Alice的数变为c,Bob的数变为d
我们先来解决平局的情况:
根据异或性质可得:若c=d,则c⊕d=0
c⊕d=X1⊕X2⊕…⊕Xn,所以要使c=d,当且仅当X1⊕X2⊕…⊕Xn=0
接下来定输赢:
我们将c,d转换成二进制数。对于二进制数的比较,我们是从高位往低位开始的。所以要使自己的数最大,就需要从高位开始
设当前枚举到二进制的第i位。设X1,X2,X3,…,Xn中一共有cnt1个数在该位的值为1,cnt0个数在该位的的值为0。(cnt1+cnt0=n) 

结论一:如果cnt1为偶数,则Alice和Bob无法在该位分出胜负(A,B分得的个数相同,c,d再该位的异或值都必然相同),反之当cnt1的个数为奇数时,必然能决出胜负 

结论二:当cnt1为奇数,cnt0=0时,先手必胜 

结论三:谁的胜率率先减少,则谁必败
结论四:当cnt1、cnt0为奇数时,且cnt1>1时先手的胜率会率先减少
结论五:当cnt1=1时,先手必胜 

代码如下: 

#include<iostream>
using namespace std;
const int N = 2e5+10;
int a[N];
int main(){
	int T, n; cin >> T;
	int sm;
	while(T--){
		cin >> n;
		sm = 0;
		for(int i=1;i<=n;i++){
			cin >> a[i];
			sm = sm ^ a[i];
		}
		if(sm==0){
			cout << 0 << endl; continue;
		}
		//检查n个整数在第j位上数码1和0的各种情况 
		for(int j=19;j>=0;j--){
			int cnt1 = 0, cnt0 = 0;  //n个整数在第j位上的数码1的数有cnt1个
			for(int i=1;i<=n;i++){
				if(a[i]>>j & 1) cnt1++;  //右移j位与1做与运算判断第j位是否为1 
				else cnt0++;
			} 
			if(cnt1&1){  //cnt1为奇数(将cnt1转化为二进制数,该二进制数的最后一位与1相与,奇数二进制的最后一位为1)
				if(cnt0%2 and cnt1!=1) //cnt0为奇数且cnt1>1则Alice输掉这场比赛 
					cout << -1 << endl;
				else //cnt0为偶数或cnt1==1
					cout << 1 << endl; 
				break;  //cnt1为奇数,在这一位一定能分出胜负 
			}
			else ;  //cnt1为偶数,当前位不能分出胜负,看下一位 
		}
	}
	
	return 0;
}
  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值