题意:给出n堆石头,现在由先手与后手进行操作,每次每个选手都可以选择一堆石子进行取出,不能不取,哪位选手面对没有石头可以取得情况就是失败了,现在先手拜输出"No",先手赢输出"Yes"。
题解:最基本的尼姆博弈,最需要了解就是必败态,到底什么是必败态。
必败态:
1.无法进行任何移动的局面是必败态
2.可以移动到必败态的局面是非必败态
3.在必败态做的任何操作的结果都是非必败态
知道了这个还是不管用,最关键还得找出必败态,这个题的必败态是a1^a2^....^an=0,证明有三:
首先看是否满足必败态条件一:当每堆的石子数都为0时,自然抑或结果也为0,满足
然后看是否满足必败态条件二:当a1^a2^....^an=k(k不等于0),则一定存在某个ai,它的二进制表示在k的最高位上是1(否则k的最高位那个1是怎么得到的)。然后a1^a2^...^ai'.^an=0,此时这个ai'=ai^k,也就是a1^a2^...^ai^...^an^k=0,并且这个ai^k<ai,这个条件是肯定的,然后也就满足条件二了。
最后看是否满足必败态条件三:当a1^a2^....^an=0时,肯定不存在操作使得a1^a2^..ai'..^an=0,可以反证下,如果a1^a2^..^ai'..^an=0,那么a1^a2^....^an=a1^a2^..^ai'..^an,然后异或操作满足消去率,把其他的消去后,也就是ai=ai',这也就是说一个都不拿么,与题意正好相反,所以在必败态下做的任何操作的结果都是非必败态。
参考了一个写的很好的解释
附上代码:
#include<iostream>
#include<cstdio>
using namespace std;
int m,a;
int main()
{
while(scanf("%d",&m)!=EOF){
int ans=0;
while(m--){
scanf("%d",&a);
ans^=a;
}
printf("%s\n",ans==0?"No":"Yes");
}
return 0;
}