• [CQOI2013]新Nim游戏


    [CQOI2013]新Nim游戏

    在Nim游戏中,限定第一回合玩家可以拿走任几堆石子,但不能全部拿完,同样第二回合选手进行同样操作,接下来的回合同Nim游戏操作,询问先手是否必胜所拿走的最少的石子。

    不难得知应该要用Nim游戏的结论,自然想到暴力建SG函数,但是注意问题只有前两个回合特殊,根据Nim定理,换一种解释即选出最多的数构成一个集合,使其任意子集异或和不为0。

    异或和问题,考虑线性基,现在我们有了如何判断异或和是否为0的工具,经验告诉我们自由选择一般不能递推,于是考虑贪心,从大到小选择,如果能够加入线性基,就选择即可,正确性证明如下。


    证明:

    假设选到第i个数(a_i),前i个数已经选到最优情况,如果不是最优的情况,必然至少存在(a_j,a_k)使其和大于(a_i),并且因为(a_i)的存在,不能加入线性基,但是(a_i)在线性基中只占一个二进制位,而因为其存在而不能选这两个数,意味着这两个数加入线性基时必然也占这一个二进制位,而位置只有一个,故显然它们会互斥,于是矛盾,得证。


    参考代码:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #define il inline
    #define ri register
    #define ll long long
    using namespace std;
    struct linear_base{
        int base[32];
        il bool insert(int x){
            ri int i;
            for(i=31;i>=0;--i)
                if(x>>i){
                    if(base[i])x^=base[i];
                    else return base[i]=x;
                }return false;
        }
    }B;int a[101];
    il void read(int&);
    int main(){
        int k,i;ll ans(0);read(k);
        for(i=1;i<=k;++i)read(a[i]);sort(a+1,a+k+1);
        for(i=k;i;--i)if(!B.insert(a[i]))ans+=a[i];
        printf("%lld",ans);
        return 0;
    }
    il void read(int &x){
        x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    }
    
    
  • 相关阅读:
    P2149 [SDOI2009]Elaxia的路线
    P1346 电车
    P3174 [HAOI2009]毛毛虫
    P3047 [USACO12FEB]附近的牛Nearby Cows
    P4053 [JSOI2007]建筑抢修
    P2607 [ZJOI2008]骑士
    [HNOI2006]马步距离
    [POI2014]Hotel
    [BZOJ3856]Monster
    [BZOJ2819]Nim
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/10859551.html
Copyright © 2020-2023  润新知