考Nim-Sum证明的,
a1^a2^a3^....^ai......^an = ans, 若ans = 0,这肯定是必败态,
win的步数为0;若ans != 0, 则为必胜态,怎样才能达到必败态呢,或者说有多少种可能达到必败态(理论上至少有1种至多有n种),而这里:
等式两边同时^ans得
a1^a2^a3^....^ai...^an^ans = 0
根据结合律:
(a1^ans)a2^a3^....^ai...^an = ... = a1^a2^a3....^(ai^ans)...^an = ... = 0
对于ai^ans < ai表明可以从ai中取走ai-ai^ans个,第i堆变为ai^ans,从而原局面也变为必败态。
总之,统计一下满足(ai^ans) < ai的ai的个数就是从当前必胜态达到必败态的不同方法数~
注意位运算的优先级(虽然看了这个题解...但是还是没注意..wa了好几次...问的别人才注意到)不仅低于算术运算(写线段树时发现的),也低于比较运算(今天才发现),括号不能少啊~~
转自:这里
代码是我自己的~~~:
#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define LL long long
#define ls v<<1
#define rs v<<1|1
//#define LOCAL
using namespace std;
const int INF=0x3ffffff;
const int MAXN=1010;
int a[MAXN],ans;
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
ios::sync_with_stdio(false);
int n;
while(cin>>n)
{
if(!n)
break;
ans=0;
for(int i=0;i<n;i++)
{
cin>>a[i];
ans^=a[i];//计算结果,判断是否是平衡态
}
if(!ans)
cout<<0<<endl;
else{
int rez=0;
for(int i=0;i<n;i++){
if((a[i]^ans)<a[i])
rez++;
}
cout<<rez<<endl;
}
}
return 0;
}