程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> HDOJ 3537 Daizhenyangs Coin (翻硬幣游戲)

HDOJ 3537 Daizhenyangs Coin (翻硬幣游戲)

編輯:C++入門知識

每次可以翻動一個、二個或三個硬幣。(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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved