bzoj 3105: [cqoi2013]新Nim游戏 异或高消 && 拟阵

mac2022-07-05  12

3105: [cqoi2013]新Nim游戏

Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 535  Solved: 317[Submit][Status][Discuss]

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集合”其实就是一个拟阵。【拟阵(E,I)1.空集满足 2.若集合A满足,则A子集满足“子集异或和非0” 3.若card(A)>card(B),存在x属于A,且B+{x}属于I,这个可以用异或高消来理解】所以按照拟阵的标准贪心思路,将读入的数列从大到小排一遍序就ok了。

  发现以前写的异或高消都有bug,整个人都splay起来了。

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MAXN 100000 typedef long long qword; int lst[MAXN]; inline bool cc(int x,int y) { for (int i=30;i>=0;i--) if (x&(1<<i)) return y&(1<<i); } int main() { freopen("input.txt","r",stdin); int n; scanf("%d",&n); for (int i=0;i<n;i++) scanf("%d",lst+i); sort(lst,lst+n,greater<int>()); qword ans=0; int x,y; for (int i=0;i<n;i++) { x=lst[i]; for (int j=0;j<i;j++) { if (cc(lst[j],lst[i])) lst[i]^=lst[j]; } if (!lst[i]) ans+=x; } printf("%lld\n",ans); }

 

转载于:https://www.cnblogs.com/mhy12345/p/4523329.html

最新回复(0)