题意:n堆stone,每堆s[i]个 s[i]<=60,n<=1e6,若从第i堆拿了x个 则第i堆不能再取x个,无法操作则输
找到i个石头的SG值,同样i个,取的石头可能有不同的限制.设dp[i][j] i表示石子数量 j表示能取的状态的SG值 O(n*2^n*logn)
最终游戏要求的异或和为:dp[i][2^i-1](i=1~n) 打表找到dp[i](2^i-1)规律即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,ll> ii;
const int M=2e6+20;
const int N=70;
map<pair<int,ll>,int> grundy;
map<pair<int,ll>,bool> mp;
int Grundy(int i,ll j)
{
if(mp[ii(i,j)])//该状态grundy已经被计算
return grundy[ii(i,j)];
vector<bool> mk(63,false);
for(int k=0;k<i;k++)//取k+1个
{
if(((j>>k)&1)==0)//状态j第k位为0,不能取k+1个
continue;
mk[Grundy((i-k-1ll),(j^(1ll<<k)))]=true;
}
int ret;
for(int k=0;k<63;k++)
{
if(mk[k]==false)
{
grundy[ii(i,j)]=k;
ret=k;
break;
}
}
mp[ii(i,j)]=true;
return ret;
}
void calc()
{
grundy[ii(0,0)]=0;
mp[ii(0,0)]=true;
vector<int> gr(70,0);
for(int i=0;i<=60;i++)
gr[i]=Grundy(i,(1ll<<i)-1ll),cout<<gr[i]<<' ';
}
int f[N];
int main()
{
//calc();
//规律 2个1,3个2,4个3.(n+1)个n
int i=0,cnt=0;
while(i<=60)
{
for(int k=0;k<=cnt;k++)
f[i++]=cnt;
cnt++;
}
int n;
while(cin>>n)
{
int x,ans=0;
for(int i=0;i<n;i++)
{
scanf("%d",&x);
ans=ans^f[x];
}
if(ans==0)
puts("YES");//后手win
else
puts("NO");
}
return 0;
}