• 【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

    题解:先手必胜的条件为剩下的火柴中不存在异或和为0的子集。

    因此我们须要寻求极大的线性无关组。答案即为总和减去极大线性无关组的权值和。

    能够证明这是一个拟阵,然后贪心就好了。贪心过程中维护线性基。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int ins[50],k,a[1001],c[1001];
    long long ans,sum;
    int main()
    {
    	scanf("%d",&k);
    	for (int i=1;i<=k;i++) scanf("%d",&a[i]);
    	sort(a+1,a+k+1);
    	for (int i=1;i<=k;i++) sum+=(long long)(c[i]=a[i]);
    	for (int i=k;i>=1;i--)
    	  {
    	  	 for (int j=30;~j;j--)
    	  	    if (a[i]&(1<<j))
    	  	     {
    	  	        if (!ins[j])
    	  	         {
    	  	           ins[j]=i;break;
    	  	         }
    	  	        else a[i]^=a[ins[j]];
    	  	     }
    		if (a[i]) ans+=(long long )c[i];
    	  }
    	printf("%lld",sum-ans);
    }


  • 相关阅读:
    逗号操作符使用小技巧
    字符解码?
    画图 wx.Window pen
    进程和线程
    内存管理
    简单的文本编辑器
    迭代器 Iterator
    文件操作
    ebay api学习
    一,wxpython入门
  • 原文地址:https://www.cnblogs.com/brucemengbm/p/6873567.html
Copyright © 2020-2023  润新知