zoukankan      html  css  js  c++  java
  • bzoj3105 [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

    正解:线性基+博弈论。

    第一次自己想出线性基的题。。好感动啊qwq!!!话说这个数据范围这么小是什么鬼。。

    我们先考虑普通的nim游戏。如果火柴堆的异或和不为0,那么先手胜,否则后手胜。那么现在有一个拿走任意堆石子的操作。我们可以考虑一下,先手拿了若干堆石子,使得后手无论如何取石子,都无法让所有石子异或和为0。那么这就很明显了,我们需要构造一个线性基,线性基以外的石子堆都要被拿走。然后我们要求拿走石子最小的方案,那这就和元素那道题的贪心很像了。我们先把石子从大到小排序,然后依次插入线性基,如果这个数最后变成了0,就把它加入答案。最后的总和就是我们要求的答案。证明。。拟阵我不会

     1 //It is made by wfj_2048~
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <complex>
     5 #include <cstring>
     6 #include <cstdlib>
     7 #include <cstdio>
     8 #include <vector>
     9 #include <cmath>
    10 #include <queue>
    11 #include <stack>
    12 #include <map>
    13 #include <set>
    14 #define inf (1<<30)
    15 #define il inline
    16 #define RG register
    17 #define ll long long
    18 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
    19 
    20 using namespace std;
    21 
    22 ll a[110],p[70],n,ans;
    23 
    24 il int gi(){
    25     RG int x=0,q=1; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    26     if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x;
    27 }
    28 
    29 il int cmp(const ll &a,const ll &b){ return a>b; }
    30 
    31 il int insert(RG ll x){
    32     for (RG int i=62;i>=0;--i)
    33     if (x>>i&1){
    34         if (!p[i]){ p[i]=x; break; }
    35         x^=p[i];
    36     }
    37     return x;
    38 }
    39 
    40 il void work(){
    41     n=gi(); for (RG int i=1;i<=n;++i) a[i]=gi();
    42     sort(a+1,a+n+1,cmp);
    43     for (RG int i=1;i<=n;++i)
    44     if (!insert(a[i])) ans+=a[i];
    45     printf("%lld
    ",ans); return;
    46 }
    47 
    48 int main(){
    49     File("nim");
    50     work();
    51     return 0;
    52 }
  • 相关阅读:
    C#编程总结(三)线程同步 多线程
    配置 Spring.NET
    C# Redis
    WPF MvvmLight RelayCommand 绑定Command 的使用
    WCF编程系列(一)初识WCF
    C#/WPF程序开机自动启动
    C# 创建Windows Service(Windows服务)程序
    前端Js框架汇总
    列式存储和行式存储
    llvm-3.4.2 编译失败 解决方案
  • 原文地址:https://www.cnblogs.com/wfj2048/p/6554248.html
Copyright © 2011-2022 走看看