码迷,mamicode.com
首页 > 其他好文 > 详细

【BZOJ】【3759】Hungergame饥饿游戏

时间:2015-02-27 16:43:31      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:

博弈论/高斯消元

  如果没有打开箱子这个操作,那么就是一个很裸的Nim游戏……

  但是有了打开箱子这个操作,就变得蛋疼了T_T

  首先我们可以想到一种直接的做法:打开所有箱子,当然如果此时所有a[i]的xor和==0则胜……

  但明显这样连样例也过不了╮(╯▽╰)╭

  那么我们可以想一下,对于一组全部没打开的箱子,我们进行一次操作后,会分成两组:打开的和没打开的(废话!)

  so sad……写不下去了……

  算了 Orz一下PoPoQQQ,搬运下题解:

技术分享
先手必胜的状态为:给出的数字集合存在一个异或和为零的非空子集,则先手必胜

证明:

首先我们有状态A:当前的所有打开的箱子中的石子数异或和为零,且所有关闭的箱子中的石子数的集合中不存在一个异或和为零的非空子集

易证A状态时先手必败

先手有两种操作:

1.从一个打开的箱子中拿走一些石子 那么根据Nim的结论 后手可以同样拿走一些石子使状态恢复为A状态

2.打开一些箱子 由于未打开的箱子中不存在一个异或和为零的非空子集 所以打开后所有打开的箱子中石子数异或和必不为零 于是后手可以拿走一些石子使状态恢复为A状态

故此时先手必败

那么如果初始不存在一个异或和为零的非空子集,那么初始状态满足状态A,先手必败

如果初始存在一个异或和为零的非空子集,那么先手一定可以打开所有的异或和为零的子集,使剩余箱子不存在异或和为零的非空子集,将状态A留给后手,先手必胜

然后就是判断有没有异或和为零的非空子集的问题了……果断高斯消元求线性基
View Code

我的代码:(一开始直接暴力枚举的子集……)

技术分享
 1 /**************************************************************
 2     Problem: 3759
 3     User: Tunix
 4     Language: C++
 5     Result: Accepted
 6     Time:8280 ms
 7     Memory:1272 kb
 8 ****************************************************************/
 9  
10 //BZOJ 3759
11 #include<cmath>
12 #include<vector>
13 #include<cstdio>
14 #include<cstring>
15 #include<cstdlib>
16 #include<iostream>
17 #include<algorithm>
18 #define rep(i,n) for(int i=0;i<n;++i)
19 #define F(i,j,n) for(int i=j;i<=n;++i)
20 #define D(i,j,n) for(int i=j;i>=n;--i)
21 #define pb push_back
22 using namespace std;
23 int getint(){
24     int v=0,sign=1; char ch=getchar();
25     while(!isdigit(ch)) {if(ch==-) sign=-1; ch=getchar();}
26     while(isdigit(ch))  {v=v*10+ch-0; ch=getchar();}
27     return v*sign;
28 }
29 const int N=1e7+10,INF=~0u>>2;
30 const double eps=1e-8;
31 /*******************template********************/
32  
33 int a[25];
34 int main(){
35 #ifndef ONLINE_JUDGE
36     freopen("input.txt","r",stdin);
37 //  freopen("output.txt","w",stdout);
38 #endif
39     int T=getint();
40     while(T--){
41         int n=getint();
42         bool ans=0;
43         rep(i,n) a[i]=getint();
44          
45         F(i,1,(1<<n)-1){
46             int tmp=0,tmp2=0;
47             rep(j,n)
48                 if (i & (1<<j)) tmp^=a[j];
49             if (tmp==0){ ans=1; break; }
50         }
51         puts(ans?"Yes":"No");
52     }
53     return 0;
54 }
View Code

高斯消元:

技术分享
 1 /**************************************************************
 2     Problem: 3759
 3     User: Tunix
 4     Language: C++
 5     Result: Accepted
 6     Time:0 ms
 7     Memory:1272 kb
 8 ****************************************************************/
 9  
10 //BZOJ 3759
11 #include<cmath>
12 #include<vector>
13 #include<cstdio>
14 #include<cstring>
15 #include<cstdlib>
16 #include<iostream>
17 #include<algorithm>
18 #define rep(i,n) for(int i=0;i<n;++i)
19 #define F(i,j,n) for(int i=j;i<=n;++i)
20 #define D(i,j,n) for(int i=j;i>=n;--i)
21 #define pb push_back
22 using namespace std;
23 int getint(){
24     int v=0,sign=1; char ch=getchar();
25     while(!isdigit(ch)) {if(ch==-) sign=-1; ch=getchar();}
26     while(isdigit(ch))  {v=v*10+ch-0; ch=getchar();}
27     return v*sign;
28 }
29 const int N=1e7+10,INF=~0u>>2;
30 const double eps=1e-8;
31 /*******************template********************/
32 int a[25];
33 bool gauss(int n){
34     rep(i,n){
35         F(j,i+1,n-1) if (a[j]>a[i]) swap(a[i],a[j]);
36         if (!a[i]) return 1;
37         D(j,20,0) if(a[i]>>j & 1){
38             rep(x,n) if(x!=i && a[x]>>j&1) a[x]^=a[i];
39             break;
40         }
41     }
42     return 0;
43 }
44 int main(){
45 #ifndef ONLINE_JUDGE
46     freopen("input.txt","r",stdin);
47 //  freopen("output.txt","w",stdout);
48 #endif
49     int T=getint();
50     while(T--){
51         int n=getint();
52         bool ans=0;
53         rep(i,n) a[i]=getint();
54         puts(gauss(n)?"Yes":"No");
55     }
56     return 0;
57 }
View Code

时间上差距也太大了!!!看来是出题人比较良心,不会高斯消元的童鞋也让过了……

【BZOJ】【3759】Hungergame饥饿游戏

标签:

原文地址:http://www.cnblogs.com/Tunix/p/4303569.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!