BZOJ3759: Hungergame 博弈论+线性基
Posted wjyi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ3759: Hungergame 博弈论+线性基相关的知识,希望对你有一定的参考价值。
学了新的忘了旧的,还活着干什么
题意:一些盒子,每步可选择打开盒子和取出已打开盒子的任意多石子,问先手是否必胜
搬运po姐的题解:
先手必胜的状态为:给出的数字集合存在一个异或和为零的非空子集,则先手必胜
证明:
首先我们有状态A:当前的所有打开的箱子中的石子数异或和为零,且所有关闭的箱子中的石子数的集合中不存在一个异或和为零的非空子集
易证A状态时先手必败
先手有两种操作:
1.从一个打开的箱子中拿走一些石子 那么根据Nim的结论 后手可以同样拿走一些石子使状态恢复为A状态
2.打开一些箱子 由于未打开的箱子中不存在一个异或和为零的非空子集 所以打开后所有打开的箱子中石子数异或和必不为零 于是后手可以拿走一些石子使状态恢复为A状态
故此时先手必败
那么如果初始不存在一个异或和为零的非空子集,那么初始状态满足状态A,先手必败
如果初始存在一个异或和为零的非空子集,那么先手一定可以打开所有的异或和为零的子集,使剩余箱子不存在异或和为零的非空子集,将状态A留给后手,先手必胜
然后就是判断是否有子集异或为0,线性基求一下。
update:其实当n>32时可以直接判断先手胜,因为int范围考虑每一个二进制位一定会有异或为0的
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 35 4 int read(){ 5 int x=0,f=1;char ch=getchar(); 6 while(ch<\'0\'||ch>\'9\'){if(ch==\'-\')f=-1;ch=getchar();} 7 while(ch>=\'0\'&&ch<=\'9\'){x=x*10+ch-\'0\';ch=getchar();} 8 return x*f; 9 } 10 int n,a[N],b[N]; 11 bool gauss(){ 12 memset(b,0,sizeof(b)); 13 for(int i=1;i<=n;i++){ 14 for(int j=30;j>=0;j--) 15 if(a[i]>>j&1){ 16 if(!b[j]){b[j]=a[i];break;} 17 else a[i]^=b[j]; 18 } 19 if(!a[i])return 1; 20 } 21 return 0; 22 } 23 int main(){ 24 int T=read(); 25 while(T--){ 26 n=read(); 27 for(int i=1;i<=n;i++)a[i]=read(); 28 puts(gauss()?"Yes":"No"); 29 } 30 return 0; 31 }
3759: Hungergame
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 182 Solved: 131
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
5
18 11 16 19 15
5
18 12 17 10 18
5
17 7 1 10 1
5
19 5 16 19 8
5
18 18 7 4 9
Sample Output
Yes
Yes
Yes
Yes
HINT
以上是关于BZOJ3759: Hungergame 博弈论+线性基的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ4889 & 洛谷3759:[TJOI2017]不勤劳的图书管理员——题解
BZOJ 1982 [Spoj 2021]Moving Pebbles(博弈论)
[Bzoj1022][SHOI2008]小约翰的游戏John(博弈论)