![watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N0cmFuZ2VERERG,size_16,color_FFFFFF,t_70](https://i-blog.csdnimg.cn/blog_migrate/85700fd9812c02fdcc2180069cb9debe.png)
- 先想一下怎么把新nim转化为nim。你发现要保证第一个人必胜,只需要让他第一次取尽量少的堆之后,第二个人无论怎样取,都无法达到第一个人必败态。(必败态即为异或和为0)。
- 所以问题转化成选出一个最大的线性无关子集,剩下的就是第一个人要取的堆。
- 贪心一下,把所有堆从大到小排序,插入线性基,每次插入一个数,减去它的权值,最后的sum就是答案。
Coding
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=200;
ll k,tmp[N],a[N],ans,sum;
bool cmp(ll a,ll b){return a>b;}
void insert(ll v){
ll temp=v;
for(int i=31;i>=0;--i) if((v>>i)&1){
if(a[i]) v^=a[i];
else{
for(int j=i-1;j>=0;--j)
if((v>>j)&1) v^=a[j];
for(int j=i+1;j<=31;++j)
if((a[j]>>i)&1) a[j]^=v;
a[i]=v;
ans-=temp;
break;
}
}
}
int main(){
scanf("%lld",&k);
for(int i=1;i<=k;++i) scanf("%lld",&tmp[i]),ans+=tmp[i],sum+=tmp[i];
sort(tmp+1,tmp+k+1,cmp);
for(int i=1;i<=k;++i) insert(tmp[i]);
if(sum==ans) printf("-1\n");
printf("%lld\n",ans);
return 0;
}