• [CQOI2013]新Nim游戏


    Description

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

    Input

    第一行为整数k。即火柴堆数。第二行包含k个不超过109的正整数,即各堆的火柴个数。
     

    Output

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

    Sample Input

    6
    5 5 6 6 5 5

    Sample Output

    21

    HINT

    k<=100

    可知异或和为0则必败,也就是说开头取掉几堆后,剩余集合不能出现异或为0的子集

    可知就是维护一个权值和最大的线性无关组(线性基)

    从大到小排序,一个个加入线性基

    如果没有成功插入,那么说明该元素与其他线性相关,即可以用线性基中的子集异或和表示

    这和元素的贪心很像

    给出拟阵证明

    我们设n个火柴堆的数目为集合S,若某个S的子集r不存在任何一个非空子集异或和0,则r∈I.下面我们证明二元组M=(S,I)是一个拟阵。
    遗传性:设A∈I,则A是S的线性无关组,则A的任意非空子集均线性无关,即对A的任意子集B,B均线性无关,因此B∈I,证毕。
    交换性:设A,B∈I,且|A|<|B|,我们要证明存在x∈B,使得A∪{x}∈I.利用反证法,假设对于任意x∈B-A,均有A∪{x}不属于I,则B-A中的元素均在A的异或空间中,可由A的子集异或和表示。
    因此B中的元素都在A的异或空间中。那么必然有B的异或空间包含于A的异或空间。由|A|<|B|且A,B线性无关,显然矛盾。因此交换性存在,证毕。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 using namespace std;
     7 typedef long long lol;
     8 int P[40],a[101],n;
     9 lol ans;
    10 int add(int x)
    11 {int i;
    12   for (i=30;i>=0;i--)
    13     if (x&(1<<i))
    14       {
    15     if (P[i]==0)
    16       {
    17         P[i]=x;
    18         break;
    19       }
    20     x^=P[i];
    21       }
    22   return x;
    23 }
    24 int main()
    25 {int i;
    26   cin>>n;
    27   for (i=1;i<=n;i++)
    28     scanf("%d",&a[i]);
    29   sort(a+1,a+n+1);
    30   for (i=n;i>=1;i--)
    31     {
    32       if (add(a[i])==0) ans+=a[i];
    33     }
    34   cout<<ans;
    35 }
  • 相关阅读:
    输出流对象
    1.2最简单的c++程序
    c++的初步认识
    理想程序员
    从字符数组中删除字符
    打印杨辉三角
    旋转数组
    找出1000以内的所有完数
    计算兔子的总数
    101-200有多少个素数?
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8391568.html
Copyright © 2020-2023  润新知