分析:
初始时,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;
}