1. 程式人生 > 其它 >hud:Being a Good Boy in Spring Festival(nim博弈方法數計算)

hud:Being a Good Boy in Spring Festival(nim博弈方法數計算)

Problem Description
一年在外 父母時刻牽掛
春節回家 你能做幾天好孩子嗎
寒假裡嘗試做做下面的事情吧

陪媽媽逛一次菜場
悄悄給爸爸買個小禮物
主動地 強烈地 要求洗一次碗
某一天早起 給爸媽用心地做回早餐

如果願意 你還可以和爸媽說
咱們玩個小遊戲吧 ACM課上學的呢~

下面是一個二人小遊戲:桌子上有M堆撲克牌;每堆牌的數量分別為Ni(i=1…M);兩人輪流進行;每走一步可以任意選擇一堆並取走其中的任意張牌;桌子上的撲克全部取光,則遊戲結束;最後一次取牌的人為勝者。
現在我們不想研究到底先手為勝還是為負,我只想問大家:
——“先手的人如果想贏,第一步有幾種選擇呢?”

Input
輸入資料包含多個測試用例,每個測試用例佔2行,首先一行包含一個整數M(1<M<=100),表示撲克牌的堆數,緊接著一行包含M個整數Ni(1<=Ni<=1000000,i=1…M),分別表示M堆撲克的數量。M為0則表示輸入資料的結束。

Output
如果先手的人能贏,請輸出他第一步可行的方案數,否則請輸出0,每個例項的輸出佔一行。


輸入樣例

3
5 7 9
0
 

輸出樣例

1


Nim的ans=g1^...gi^gn;ans=0時必敗點
方法數與ans的最高位上1的個數相同
附ac程式碼
#include<bits/stdc++.h>
using namespace std;
int er[110][40];
void turn(int i,int t)
{
    int z=0;
    while(t>0)
    {
        er[i][z++]=t%2;
        t/=2;
    }
}
int turn1(int t) { int z=0; while(t>0) { z++; t/=2; } return z-1; } int main(void) { int m; while(scanf("%d",&m),m) { int k; int ans=0,maxn=-1,w,sum=0; memset(er,0,sizeof(er)); for(int i=0;i<m;++i) { scanf("%d",&k); ans
^=k; turn(i,k); } if(ans==0) { printf("0\n"); continue; } else { w=turn1(ans); for(int i=0;i<m;++i) if(er[i][w]==1) sum++; printf("%d\n",sum); } } return 0; }