每次可以翻動一個、二個或三個硬幣。(Mock Turtles游戲)
初始編號從0開始。
當N==1時,硬幣為:正,先手必勝,所以sg[0]=1.
當N==2時,硬幣為:反正,先手必贏,先手操作後可能為:反反或正反,方案數為2,所以sg[1]=2。
當N==3時,硬幣為:反反正,先手必贏,先手操作後可能為:反反反、反正反、正反正、正正反,方案數為4,所以sg[2]=4。
位置x:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14...
sg[x]: 1 2 4 7 8 11 13 14 16 19 21 22 25 26 28…
看上去sg值為2x或者2x+1。我們稱一個非負整數為odious,當且僅當該數的二進制形式的1出現的次數是奇數,否則稱作evil。所以1,2,4,7是odious因為它們的二進制形式是1,10,100,111.而0,3,5,6是evil,因為它們的二進制形式是0,11,101,110。而上面那個表中,貌似sg值都是odious數。所以當2x為odious時,sg值是2x,當2x是evil時,sg值是2x+1.
這樣怎麼證明呢?我們會發現發現,
evil^evil=odious^odious=evil
evil^odious=odious^evil=odious
假設剛才的假說是成立的,我們想證明下一個sg值為下一個odious數。注意到我們總能夠在第x位置翻轉硬幣到達sg為0的情況;通過翻轉第x位置的硬幣和兩個其它硬幣,我們可以移動到所有較小的evil數,因為每個非零的evil數都可以由兩個odious數異或得到;但是我們不能移動到下一個odious數,因為任何兩個odious數的異或都是evil數。
假設在一個Mock Turtles游戲中的首正硬幣位置x1,x2,…,xn是個P局面,即sg[x1]^…^sg[xn]=0.那麼無可置疑的是n必定是偶數,因為奇數個odious數的異或是odious數,不可能等於0。而由上面可知sg[x]是2x或者2x+1,sg[x]又是偶數個,那麼x1^x2^…^xn=0。相反,如果x1^x2^…^xn=0且n是偶數,那麼sg[x1]^…^sg[xn]=0。這個如果不太理解的話,我們可以先這麼看下。2x在二進制當中相當於把x全部左移一位,然後補零,比如說2的二進制是10,那麼4的二進制就是100。而2x+1在二進制當中相當於把x全部左移一位,然後補1,比如說2的二進制是10,5的二進制是101。現在看下sg[x1]^…^sg[xn]=0,因為sg[x]是2x或者2x+1,所以式子中的2x+1必須是偶數個(因為2x的最後一位都是0,2x+1的最後一位都是1,要最後異或為0,2x+1必須出現偶數次)。實際上的情況可能是這樣的:
MT游戲當中的P局面是擁有偶數堆石子的Nim游戲的P局面。
雖然看不太懂,但是有上面的結論就夠了,找到每個位置的SG值,然後異或
被戴神的女友坑了,還要排序判重,ORZ。
[cpp]
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<vector>
#define C 240
#define TIME 10
#define inf 1<<25
#define LL long long
using namespace std;
int main(){
int n,a[100];
while(scanf("%d",&n)!=EOF){
int ret=0,k;
if(n==0){
puts("Yes");
continue;
}
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
int len=1;
for(int i=1;i<n;i++)
if(a[i]!=a[len-1])
a[len++]=a[i];
for(int i=0;i<len;i++){
int k=a[i];
int cnt=0,t=2*k;
while(k){
if(k&1)
cnt++;
k>>=1;
}
if(cnt%2==0)
ret^=t+1;
else
ret^=t;
}
puts(ret?"No":"Yes");
}
return 0;
}
作者:ACM_cxlove