hdu 1850 Being a Good Boy in Spring Festival (尼姆博弈)

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,每个实例的输出占一行。
 

Sample Input

     
     
     
     
3 5 7 9 0
 

Sample Output

     
     
     
     
1
 

解题报告:题目的意思很简单!就是一个Nim博弈!但是不是问谁获胜,本题而是问的获胜的方法有多少种!首先,我们必须知道,因为是先手,对于M堆扑克,最多有M种获胜的方法!对res = M1 ^ M2 ^ M3 …. ^ Mm取异或(^)得res,由异或的性质知:res ^ Mi = ( M1 ^ M2 …^M(i-1) ^ M(i+1) ^ … ^Mm ) 也就是说res对任意一个数取^可以得到其他所有数的^值,例如:5 7 95^7^9=0101^0111^1001=1011=11;那么11^5=1011^0101=1110=0111^1001=14;那么要保证先手取后剩余局势处于必败点,那么只有保证在这5张牌的牌堆里取出一些牌后,可以使得x^1110=0x=1110=14那么也就是说这个牌堆数必须大于14才有可能达到这种状态;现在只有5张牌,显然不能,而对于牌堆9,有(res^9=0010=29显然大于2,所以只需要拿走7张牌就可以让局势处于必败点!

 

所有的按位与res和N[i]的按位与 等于 除N[i]以外的所有堆的按位与,此值若小于N[i],则只要在N[i]中取出一定的值,就能形成奇异局势(先手必输,后手必赢的状态)

#include <iostream> using namespace std; int main() {     int n;     while(cin>>n&&n!=0)     {         int N[110],i;         int res=0,ans=0;         for(i=0;i<n;i++)         {             cin>>N[i];             res=res^N[i];         }         for(i=0;i<n;i++)         {             if(N[i]>(res^N[i]))                 ans++;         }         cout<<ans<<endl;     }     return 0; }

你可能感兴趣的:(hdu 1850 Being a Good Boy in Spring Festival (尼姆博弈))