• [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();
    }
    
    
  • 相关阅读:
    Proteus仿真与实际的差别
    用 Proteus学习51单片机之1602液晶
    用Proteus学习51单片机之中断
    用Proteus学习51单片机之键盘
    用Proteus学习51单片机之数码管
    PHPnow 安装服务 [ Apache_pn ] 失败的解决方法 for[windows7/vista]
    chrome 不能打印背景图的解决方法
    JS 无块级作用域
    IE6下zindex犯癫不起作用bug的初步研究
    ie6下的js调试工具companion.js
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/10859551.html
Copyright © 2020-2023  润新知