[CQOI2013]新Nim游戏

传送门

首先,我们可以发现,只要在第一次我们自己拿的时候,使得对方无论怎么拿都不能使异或和为0即可获胜。 考虑到线性基任意一个非空子集的异或和不为0,那么我们只要给对方留下一个线性基即可。所以先手必胜。

之后考虑怎么让代价最小。这个也很简单,我们仿照上一道题目的做法,优先插入权值大的堆。每次判断一下这个是否会被线性基异或出来,如果能的话,那么就要选取他。

看一下代码。

#include <bits/stdc++.h>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
using namespace std;
typedef long long ll;

ll k,a[105],p[30],ans;

bool pd(ll x)
{
    ll b = x;
    per(i,60,0)
    {
        if((x ^ p[i]) < x) x ^= p[i];
        if(!x) {ans += b;return 1;}
    }
    return 0;
}

void insert(ll x)
{
    per(i,60,0)
    {
        if(!((x >> i) & 1)) continue;
        if(!p[i]) {p[i] = x; break;}
        x ^= p[i];
    }
}

int main()
{
    scanf("%lld",&k);
    rep(i,1,k) scanf("%lld",&a[i]);
    sort(a+1,a+1+k);
    per(i,k,1) if(!pd(a[i])) insert(a[i]);
    printf("%lld
",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/captain1/p/10211435.html