博弈论/高斯消元
如果没有打开箱子这个操作,那么就是一个很裸的Nim游戏……
但是有了打开箱子这个操作,就变得蛋疼了T_T
首先我们可以想到一种直接的做法:打开所有箱子,当然如果此时所有a[i]的xor和==0则胜……
但明显这样连样例也过不了╮(╯▽╰)╭
那么我们可以想一下,对于一组全部没打开的箱子,我们进行一次操作后,会分成两组:打开的和没打开的(废话!)
so sad……写不下去了……
算了 Orz一下PoPoQQQ,搬运下题解:
先手必胜的状态为:给出的数字集合存在一个异或和为零的非空子集,则先手必胜 证明: 首先我们有状态A:当前的所有打开的箱子中的石子数异或和为零,且所有关闭的箱子中的石子数的集合中不存在一个异或和为零的非空子集 易证A状态时先手必败 先手有两种操作: 1.从一个打开的箱子中拿走一些石子 那么根据Nim的结论 后手可以同样拿走一些石子使状态恢复为A状态 2.打开一些箱子 由于未打开的箱子中不存在一个异或和为零的非空子集 所以打开后所有打开的箱子中石子数异或和必不为零 于是后手可以拿走一些石子使状态恢复为A状态 故此时先手必败 那么如果初始不存在一个异或和为零的非空子集,那么初始状态满足状态A,先手必败 如果初始存在一个异或和为零的非空子集,那么先手一定可以打开所有的异或和为零的子集,使剩余箱子不存在异或和为零的非空子集,将状态A留给后手,先手必胜 然后就是判断有没有异或和为零的非空子集的问题了……果断高斯消元求线性基
我的代码:(一开始直接暴力枚举的子集……)
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 }
高斯消元:
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 }
时间上差距也太大了!!!看来是出题人比较良心,不会高斯消元的童鞋也让过了……
时间: 2024-09-30 20:33:31