Alice 和 Bob 正在玩一个异或数列的游戏。
初始时,Alice 和 Bob 分别有一个整数 a 和 b(初始时,a,b 均为 0),有一个给定的长度为 n 的公共数列 X1,X2,⋅⋅⋅,Xn。
Alice 和 Bob 轮流操作,Alice 先手,每步可以在以下两种选项中选一种:
- 选项 11:从数列中选一个 Xi 给 Alice 的数异或上,或者说令 aa 变为 a⊕Xi(其中 ⊕⊕ 表示按位异或)
- 选项 22:从数列中选一个 Xi 给 Bob 的数异或上,或者说令 bb 变为 b⊕Xi
每个数 Xi 都只能用一次,当所有 Xi 均被使用后(nn 轮后)游戏结束。
游戏结束时,拥有的数比较大的一方获胜,如果双方数值相同,即为平手。
现在双方都足够聪明,都采用最优策略,请问谁能获胜?
输入格式
每个评测用例包含多组询问。询问之间彼此独立。
输入的第一行包含一个整数 T,表示询问数。
接下来 T 行每行包含一组询问。其中第 ii 行的第一个整数 nini 表示数列长度,随后 ni 个整数 X1,X2,⋅⋅⋅,Xni 表示数列中的每个数。
输出格式
输出 T 行,依次对应每组询问的答案。
每行包含一个整数 1、0 或 −1 分别表示 Alice 胜、平局或败。
1 ^ x = 反转x的每一位数字, 0 ^ x = x
01-如果一组数据中每个数字全都按位异或,如果最终的结果是0则说明是平局(无法去改变a和b)输出 0
02
<1>从高位向低位枚举如果第一个1所在的最高的那一位只有一个1,那么这个1一定会被alice先选出来,又因为最高位是1所以最终alice的结果一定比bob大 输出 1
<2>如果在最高位的1出现的次数大于1此时就可以用0来滞空(即停留不选)如果0的数量为偶数那么最终还是会由alice选出奇数次的1(因为选偶数次1相当于反转两次不变)所以此时alice赢输出 1
<3>如果在最高位的1出现的次数大于1而0的个数为奇数那么此时一定是bob选到了奇数次的1所以bob赢输出 -1
03 - 判断0的个数的方法
如果在某一位的1的数量有 cnt 个, 那么等同于有cnt个数字这一位是1又因为有n个数字,所以就有n - cnt个数字这一位是0
Source Code
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 200010;
int a[N];
int pe[30];
void pre(int ai)
{
int cnt = 0;
for(int i = 0; i <= 19; i++)
{
if(ai >> i & 1) pe[cnt] ++;
cnt++;
}
}
int t, n, x;
int main()
{
// #ifdef LOCAL
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
// #endif
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> t;
while(t--)
{
cin >> n;
for(int i = 0; i < n; i++)
{
cin >> a[i];
pre(a[i]);
x ^= a[i];
}
// for(int i = 0; i <= 19; i++)
// cout << pe[i] << ' ';
// return 0;
if(!x)
cout << 0 << endl;
else
{
for(int i = 19; i >= 0; i--)
{
if(pe[i] % 2 == 0) continue;
else if(pe[i] == 1) {cout << 1 << endl; break;}
else if((n - pe[i]) % 2 == 0) {cout << 1 << endl; break;}
else if((n - pe[i]) % 2 == 1) {cout << -1 << endl; break;}
}
}
memset(pe, 0, sizeof pe);
x = 0;
}
return 0;
}