洛谷 P4301 [CQOI2013]新Nim游戏 解题报告

P4301 [CQOI2013]新Nim游戏

题目描述

传统的Nim游戏是这样的:有一些火柴堆,每堆都有若干根火柴(不同堆的火柴数量可以不同)。两个游戏者轮流操作,每次可以选一个火柴堆拿走若干根火柴。可以只拿一根,也可以拿走整堆火柴,但不能同时从超过一堆火柴中拿。拿走最后一根火柴的游戏者胜利。

本题的游戏稍微有些不同:在第一个回合中,第一个游戏者可以直接拿走若干个整堆的火柴。可以一堆都不拿,但不可以全部拿走。第二回合也一样,第二个游戏者也有这样一次机会。从第三个回合(又轮到第一个游戏者)开始,规则和Nim游戏一样。

如果你先拿,怎样才能保证获胜?如果可以获胜的话,还要让第一回合拿的火柴总数尽量小。

输入输出格式

输入格式:

第一行为整数\(k\)。即火柴堆数。

第二行包含\(k\)个不超过\(10^9\)的正整数,即各堆的火柴个数。

输出格式:

输出第一回合拿的火柴数目的最小值。如果不能保证取胜,输出\(-1\)


你不能让对面拿的使\(SG\)异或和为\(0\)

然后发现让整个异或集合线性无关就行了,就是形成一组基底。

然后我就傻了..居然写了边交换边插入

事实先排序就行了,从大的开始插入...


Code:

#include <cstdio>
#include <algorithm>
#define ll long long
int n,a[105],base[32];
ll ans;
int Insert(int x)
{
    for(int i=30;~i;i--)
        if(x>>i&1)
        {
            if(base[i]) x^=base[i];
            else {base[i]=x;return 1;}
        }
    return 0;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",a+i);
    std::sort(a+1,a+1+n);
    for(int i=n;i;i--) ans=ans+(Insert(a[i])?0:a[i]);
    printf("%lld\n",ans);
    return 0;
}

2018.12.23

posted @ 2018-12-23 17:50  露迭月  阅读(128)  评论(0编辑  收藏  举报