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 }

 

posted @ 2018-10-04 19:10  Xu-daxia  阅读(311)  评论(0编辑  收藏  举报