Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 623 Accepted Submission(s): 288
题意:Alice和Bob轮流取N堆石子,每堆S[i]个,Alice先,每一次可以从任意一堆中拿走任意个石子,也可以将一堆石子分为两个小堆。先拿完者获胜。
数据范围: (1 ≤ N ≤ 10^6, 1 ≤ S[i] ≤ 2^31 - 1).
思路: 此题为博弈中的—取走-分割游戏(这种游戏允许取走某些东西,然后将原来的一个游戏分成若干个相同的游戏)
由于数据范围,不能直接求sg值只能打表找规律;
有SJ 定理:
对于任意的一个 Anti-SG 游戏,如果我们规定当局面中所有单一游戏的 SG 值为 0 时游戏 结束,则先手必胜当且仅当以下两个条件满足任意一个:
(1)游戏的 SG 函数不为 0,且游戏中某个单一游戏的 SG 函数大于1。
(2)游戏的 SG 函数为 0,且游戏中没有单一游戏的 SG 函数大于 1。
Lasker's Nim游戏:每一轮允许两会中操作之一:①、从一堆石子中取走任意多个,②、将一堆数量不少于2的石子分成都不为空的两堆。
分析:很明显:sg(0) = 0,sg(1) = 1。
状态2的后继有:0,1和(1,1),他们的SG值分别为0,1,0,所以sg(2) =2。
状态3的后继有:0、1、2、(1,2),他们的SG值分别为0、1、2、3,所以sg(3) = 4。
状态4的后继有:0、1、2、3、(1,3)和(2,2),他们的SG值分别为0,1,2,4,5,0,所以sg(4) = 3.
再推一些,推测得到:对于所有的k >= 0,有 sg( 4k+1 ) = 4k+1; sg( 4k+2 ) = 4k+2; sg( 4k+3 ) = 4k+4; sg( 4k+4 ) = 4k+3。
假设游戏初始时有3堆,分别有2、5和7颗石子。三堆的SG函数值分别为2、5、8,他们的Nim和等于15.所以要走到P状态,就要使得第三堆的SG值变成7,可以将第三对按1和6分成两堆。
SG打表代码:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> using namespace std; const int N=1000010; int sg[N]; int g(int x){ int mex[1010]; memset(mex,0,sizeof(mex)); if(sg[x]!=-1) return sg[x]; for(int i=x-1;i>=0;i--) mex[g(i)]=1; for(int i=1;i<=x/2;i++){ int ans=0; ans^=g(i); ans^=g(x-i); mex[ans]=1; } for(int i=0;;i++) if(!mex[i]) return sg[x]=i; } int main(){ freopen("input.txt","r",stdin); int t,n; scanf("%d",&t); memset(sg,-1,sizeof(sg)); while(t--){ scanf("%d",&n); int x; for(int i=0;i<n;i++){ scanf("%d",&x); g(x); printf("sg[%d]=%d\n",x,sg[x]); } for(int i=0;i<=100;i++){ printf("%d ",sg[i]); //if(i%10==0) //system("pause"); } printf("\n"); } return 0; }
可得规律:sg(4k)=4k-1;sg(4k+1)=4k+1;sg(4k+2)=4k+2;sg(4k+3)=4k+4;
本题AC代码:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> using namespace std; int main(){ //freopen("input.txt","r",stdin); int t,n; scanf("%d",&t); while(t--){ scanf("%d",&n); int ans=0,x; for(int i=0;i<n;i++){ scanf("%d",&x); if(x%4==0) ans^=(x-1); else if(x%4==1 || x%4==2) ans^=x; else ans^=(x+1); } if(ans!=0) puts("Alice"); else puts("Bob"); } return 0; }