桌子上有M堆扑克牌;每堆牌的数量分别为Ni(i=1…M);两人轮流进行;每走一步可以任意选择一堆并取走其中的任意张牌;桌子上的扑克全部取光,则游戏结束;最后一次取牌的人为胜者。
现在我们不想研究到底先手为胜还是为负,我只想问大家:
现在我们不想研究到底先手为胜还是为负,我只想问大家:
——“先手的人如果想赢,第一步有几种选择呢?”
题解:先看nim-sum定理:
当nim游戏的某个位置:(x1,x2,x3),当且仅当其各部分的nim-sum = 0(即x1⊕x2⊕x3 = 0(也就是各部分的异或为0))
当前位置为必败点,这对于多个堆的情况同样适用。
有了这个东西就好办了,我们首先求出所有堆异或后的值,再用这个值去对每一个堆进行异或,令res = x1⊕sum(sum为所有堆的或异值)
如果res < x1的话,当前玩家就从x1中取走(x1-res)个,使x1乘下res这样必然导致所有的堆的异或值为0,也就是必败点,这就是一种方案
遍历每一个堆,进行上面的断判就可以得到总的方案数。
#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<vector>
#include<algorithm>
#define LL long long
#define maxn 10001
#define INF 2147483646
using namespace std;
int main()
{
vector<int>v;
int n,sum,count;
while(cin>>n,n)
{
count=sum=0;
v.clear();
int x;
for(int i=0;i<n;i++)
{
cin>>x;
sum^=x; //异或
v.push_back(x);
}
for(vector<int>::size_type i = 0 ;i!=v.size();i++)
{
x=v[i]^sum;
if(x<v[i])
count++;
}
cout<<count<<endl;
}
}