POJ 2311 Cutting Game(SG函数)
题目描述
意思就是说两个人轮流剪纸片,直到有一个人剪出1*1的方格就算这个人赢了。然后给出纸片的长和宽,求先手会赢还是会输
(1<=n,m<=200)
题解
看了一眼,这不是裸的SG吗
啪啪啪写完,一交T了,居然没算复杂度就交了。。。
首先明确,把纸片分成两部分之后的SG是分成两个纸片的异或。
一个非常自然的想法就是,枚举如何分割这个纸片,然后求mex。
但是这样显然会T。(200^4)
其实作为一个正常人,1*x这样的纸片是不会切出来的,这显然是一个必败局面。
然后2*2,2*3,3*2这样的局面也是必败的,搜到这样的局面就可以退出了。
最后,比如一个5*5的纸片,切成3*5+2*5和切成2*5+3*5是一样的。
所以一个x*y的纸片枚举的时候从2枚举到x/2就行。
这样就能AC了
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 const int N=210; 8 int sg[N][N],a[N*2],n,m; 9 int get_sg(int x,int y){ 10 if(sg[x][y]!=-1)return sg[x][y]; 11 bool a[250]; 12 memset(a,0,sizeof(a)); 13 for(int i=2;i<=x-i;i++)a[get_sg(i,y)^get_sg(x-i,y)]=1; 14 for(int i=2;i<=y-i;i++)a[get_sg(x,i)^get_sg(x,y-i)]=1; 15 for(int i=0;;i++){ 16 if(a[i]==0)return sg[x][y]=i; 17 } 18 } 19 int main(){ 20 memset(sg,-1,sizeof(sg)); 21 sg[2][2]=sg[3][2]=sg[2][3]=0; 22 while(scanf("%d%d",&n,&m)!=EOF){ 23 if(get_sg(n,m)==0)printf("LOSE\n"); 24 else printf("WIN\n"); 25 } 26 return 0; 27 }