如果yes的话要输出所有情况,一开始觉得挺难,想了一下也没什么。
每堆的个数^一下,答案不是0就是先取者必胜,那么对必胜态显然至少存在一种可能性使得当前局势变成必败的。只要任意选取一堆,把这堆的数目变成其他堆异或和即可,这样,它们异或一下就是0了(变成了必败态)。所以说,在这题就是,对任意一堆,变化以后的数目如果不大于这堆原来的数目,就是可能的第一次取的情况。代码如下:
1 #include <stdio.h> 2 #include <algorithm> 3 using namespace std; 4 const int N = 200000 + 5; 5 int a[N]; 6 int main() 7 { 8 int n; 9 while(scanf("%d",&n)==1 && n) 10 { 11 int temp = 0; 12 for(int i=1;i<=n;i++) {scanf("%d",a+i);temp^=a[i];} 13 if(temp == 0 ) 14 { 15 puts("No"); 16 continue; 17 } 18 else 19 { 20 puts("Yes"); 21 for(int i=1;i<=n;i++) 22 { 23 int other = a[i]^temp; 24 int x = other^0; 25 if(x <= a[i]) 26 { 27 printf("%d %d ",a[i],x); 28 } 29 } 30 } 31 } 32 }
同时,nim博弈转化成sg来理解也是没有问题的,每一堆的sg函数怎么计算的呢?显然对一堆,个数为n的话,因为可以取>=1的任意个数,所以n的后续态为0~n-1的连续整数,那么sg[n]=mex{sg[0],sg[1],...,sg[n-1]}。而sg[0]=0,sg[1]=mex{sg[0]}=mex{0}=1, sg[2]=mex{sg[0],sg[1]}=mex{0,1}=2... 因此可以递推得到sg[n]=n。所以根据sg胜利的条件是所有sg值相异或不为0,这正是nim博弈下胜利的条件。