题目大意: 现在有n堆石子,先手和后手可以先进行一次操作——取走若干堆石子,不能取完所有石子,然后进行nim游戏。现在问先手最少取走多少石子可以使得自己必胜。
因为要进行nim游戏并保证先手必胜,那么先手和后手分别取完石子堆后,剩下的石子堆的异或和肯定不为 0 0 0,但是先手取完石子堆后,后手肯定会尽量石子堆的异或和为 0 0 0,也就是说,先手取完后,剩下的石子堆需要满足——从中取任意堆,异或和都不为 0 0 0。
那么这个可以用线性基来搞,因为线性基中的元素是不可能异或出 0 0 0的。
因为要使取走的石子数最少,又因为能插入线性基内的数的个数是固定的(证明在上面的博客中),所以优先插入最大的石子堆即可。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,a[110];
int d[70];
bool add(int x)
{
for(int i=30;i>=0;i--)
{
if((x&(1<<i))>0)
{
if(d[i]==0)
{
d[i]=x;
return true;
}
else x^=d[i];
}
}
return false;
}
int main()
{
scanf("%d",&n);
if(n<=0)
{
printf("-1");
return 0;
}
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
long long ans=0;
for(int i=n;i>=1;i--)
if(!add(a[i]))ans+=(long long)a[i];//假如插入不进去
printf("%lld",ans);
}