• BZOJ-3105: 新Nim游戏 (nim博弈&线性基)


    pro:

    传统的Nim游戏是这样的:有一些火柴堆,每堆都有若干根火柴(不同堆的火柴数量可以不同)。两个游戏者轮流操作,每次可以选一个火柴堆拿走若干根火柴。可以只拿一根,也可以拿走整堆火柴,但不能同时从超过一堆火柴中拿。拿走最后一根火柴的游戏者胜利。
    本题的游戏稍微有些不同:在第一个回合中,第一个游戏者可以直接拿走若干个整堆的火柴。可以一堆都不拿,但不可以全部拿走。第二回合也一样,第二个游戏者也有这样一次机会。从第三个回合(又轮到第一个游戏者)开始,规则和Nim游戏一样。
    如果你先拿,怎样才能保证获胜?如果可以获胜的话,还要让第一回合拿的火柴总数尽量小。
     

    Input
    第一行为整数k。即火柴堆数。第二行包含k个不超过109的正整数,即各堆的火柴个数。
     
     
    sol:不会,但是看了题解觉得很简单系列。先手留给后手的状态,不能转移到状态为0。  我们知道线性无关:对于任意向量,不能被其他向量表示。 即,线性基没有异或和为0的子集。   那么我们留给对方一个最大的线性即,即可。
    先排个序,然后建立线性基。 (证明需用到拟阵,我不会)
    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=2000;
    ll ans,sum; int a[maxn],base[maxn];
    int main()
    {
        int N; scanf("%d",&N);
        rep(i,1,N) scanf("%d",&a[i]),sum+=a[i];
        sort(a+1,a+N+1);
        for(int i=N;i>=1;i--){
            int tmp=a[i];
            for(int j=30;j>=0;j--){
                if(a[i]&(1<<j)){
                    if(!base[j]){
                        base[j]=a[i];
                        break;
                    }
                    else a[i]^=base[j];
                }
            }
            if(a[i]) ans+=tmp;
        }
        printf("%lld
    ",sum-ans);
        return 0;
    }
     
  • 相关阅读:
    hdu 1199 Color the Ball 离散线段树
    poj 2623 Sequence Median 堆的灵活运用
    hdu 2251 Dungeon Master bfs
    HDU 1166 敌兵布阵 线段树
    UVALive 4426 Blast the Enemy! 计算几何求重心
    UVALive 4425 Another Brick in the Wall 暴力
    UVALive 4423 String LD 暴力
    UVALive 4872 Underground Cables 最小生成树
    UVALive 4870 Roller Coaster 01背包
    UVALive 4869 Profits DP
  • 原文地址:https://www.cnblogs.com/hua-dong/p/10791414.html
Copyright © 2020-2023  润新知