先手必胜态:可以走到某一个必败状态
先手必败态:无法走到一个必胜状态
定理:如果初始所有值的异或结果不为0,则先手必胜,反之必败
证明:
①败的最终状态0^0^0^0…=0
②当a[1] ^ a[2] ^ … ^ a[n] = x != 0 时
记x的二进制表示中最高位的1是第k位,则肯定存在一个a[i]的第k位为1(因为要使两个数异或结果为1,必然要有一个1)
可知a[i]^x < a[i](因为x的最高位的1在k,第k位都为1,因此异或后第k为0,比k位低的异或结果不管是怎么样的,最终结果肯定比a[i])
因此可以把a[i]变成a[i]^x ,即从a[i]中拿走a[i]-a[i]^x个
这样结果会变成a[1] ^ a[2] ^ … ^ a[i] ^ x ^ … ^ a[n] = 0
②当a[1] ^ a[2] ^ … ^ a[n]= 0 (式1)时
当从任意一堆中拿走任何数量的石子后,异或结果肯定不等于0
反证法证明:
若从任意一堆a[i]中拿走任何数量的石子后(a[i]变成a[t]),异或结果等于0,则a[1] ^ a[2] ^ … ^ a[t] ^ … a[n] = 0(式2)
则 式1^式2 = 0 -> a[t] ^ a[i] = 0 -> a[t] = a[i] , 这与a[i] > a[t]矛盾,因此假设不成立
因此若先手的状态为②,那么总存在一种取法,使得结果变成③,当③变成①的状态时,后手的人无法操作,先手胜利
反之同理。
所以证得:如果初始所有值的异或结果不为0,则先手必胜,反之必败
C++ 代码
#include <iostream>
using namespace std;
const int N = 100010;
int n;
int main()
{
int res = 0;
cin >> n;
while(n--)
{
int x;
cin >> x;
res ^= x;
}
if(res) puts("Yes");
else puts("No");
return 0;
}
tql 比前面那几个更容易理解