本文借鉴了蓝桥杯2021年第十二届省赛-异或数列_异或后若小于原先数则输出0,大于则输出1-优快云博客的思路,记录了自己对一些难点的理解和概括,侵删
思路
- 异或,每一位单独考虑。0异或上谁都不变,1异或上谁取反
- 判胜负就是看谁的最高位1更高
- 对于一位,如果有偶数个1——最后二人的值要么都是奇数个1异或的结果,要么都是偶数个1异或的结果,一定相同。
- 如果有奇数个1
①如果只有一个1,Alice必胜
②如果总牌数为奇数:Alice拿1与自己异或,处于胜态(1,0),剩下偶数个1、0,且Alice成为后手。Bob若拿1与自己异或,Alice可以拿1消灭Bob;Bob若拿1与Alice异或,Alice可以又拿1与自己异或;Bob若拿0与Alice或自己异或,Alice也拿0即可保持胜态。Alice必胜。
③如果总牌数为偶数:第一轮,如果Alice拿0,Bob拿1;如果Alice拿1,Bob拿0,则Bob可以使第一轮过后的状态是(0,1)或(1,0),且剩偶数个1,偶数个0,且Bob处于后手。如果是(0,1),那么现在的Bob相当于②中处于胜态(1,0)的Alice,胜态可以保持。如果是(1,0),先举个特例:比如剩2个1,零个0,Alice虽然是胜态但只能选择用1让自己为0或让Bob为1,即变为(1,1)或(0,0),Bob用最后一个1就可以让状态变成(0,1)。偶数个1,偶数个0其实同理,因为Alice取0后Bob跟随取0,那么最后0就是零个;偶数个1相当于2个1的重复。Bob必胜。
代码
统计二进制下每一位的1的个数,然后从高位遍历下去判胜负。(蓝桥云课题目里的0≤Xi<20^20应为2^20)
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const int N = 1e6 + 1;
int cnt1[21];
void add_cnt(int x) {
int k = 1;
while (x) {
if (x & 1) cnt1[k]++;
x >>= 1;
k++;
}
}
int main()
{
IOS;
int t;
cin >> t;
while (t--) {
memset(cnt1, 0, sizeof(cnt1));
int n, x;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> x;
add_cnt(x);
}
int i;
for (i = 20; i > 0; i--) {
if (cnt1[i]&1) {
if (cnt1[i] == 1||n&1) cout << 1 << endl;
else cout << -1 << endl;
break;
}
}
if (i == 0) cout << 0 << endl;
}
return 0;
}