题意:有n个格子排成一行,其中一些格子里面有字符X。两个游戏者轮流操作,每次可以选一个空格,在里面放上字符X。
如果此时有3个连续的X出现,则该游戏者赢得比赛。初始条件下不会有3个X连续出现。
判断先手胜负情况,若必胜则升序输出先手第一步的所有可选必胜策略
n<=200
思路:如果有XX或者X.X出现则一定先手胜
一个结论:X的旁边和旁边的旁边不能放X
于是整个游戏被不能放X的区域分成了若干个独立的片段,每次都可以选择一个片段进行游戏,就是若干个游戏的和
由于每个棋盘片段都是连续的,想到用一个正整数(即长度)来表示状态,g(x)表示由连续的x个格子组成的棋盘所对应的SG函数值
则有递推方程g(x)=mex(g(x-3),g(x-4),g(x-5),g(1)^g(x-6),g(2)^(x-7)……)
有了g函数,很容易算出初始局面的SG函数,所有使得后继专题SG值为0的决策即为所求
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 typedef long long ll; 7 using namespace std; 8 #define N 21000 9 #define oo 10000000 10 #define MOD 1000000007 11 12 int g[N],flag[N],b[N],c[N],d[N],n; 13 char a[N]; 14 15 int isok(int x) 16 { 17 int k=0; 18 a[x]='X'; 19 for(int i=2;i<=n-1;i++) 20 { 21 if(a[i]=='X'&&a[i+1]=='X'&&a[i-1]=='.'){k=i-1; break;} 22 if(a[i]=='X'&&a[i-1]=='X'&&a[i+1]=='.'){k=i+1; break;} 23 if(a[i]=='.'&&a[i-1]=='X'&&a[i+1]=='X'){k=i; break;} 24 } 25 if(k) 26 { 27 a[x]='.'; 28 return 0; 29 } 30 for(int i=1;i<=n;i++) b[i]=0; 31 for(int i=1;i<=n;i++) 32 if(a[i]=='X') 33 for(int j=-2;j<=2;j++) 34 if(i+j>0&&i+j<=n) b[i+j]=1; 35 int ans=0; 36 int s=0; 37 for(int i=1;i<=n;i++) 38 if(b[i]==0) s++; 39 else if(s) 40 { 41 ans^=g[s]; 42 s=0; 43 } 44 if(s) ans^=g[s]; 45 a[x]='.'; 46 if(ans) return 0; 47 return 1; 48 } 49 50 int main() 51 { 52 //freopen("uva10561.in","r",stdin); 53 //freopen("uva10561.out","w",stdout); 54 g[0]=0; 55 g[1]=g[2]=g[3]=1; 56 g[4]=g[5]=2; 57 for(int i=6;i<=200;i++) 58 { 59 memset(flag,0,sizeof(flag)); 60 for(int j=3;j<=5;j++) flag[g[i-j]]=1; 61 for(int j=6;j<=i;j++) 62 if(i-j>=0) flag[g[j-5]^g[i-j]]=1; 63 int j=0; 64 while(flag[j]) j++; 65 g[i]=j; 66 } 67 //for(int i=1;i<=200;i++) printf("%d %d ",i,g[i]); 68 int cas; 69 scanf("%d",&cas); 70 while(cas--) 71 { 72 scanf("%s",a+1); 73 n=strlen(a+1); 74 for(int i=1;i<=n;i++) d[i]=0; 75 for(int i=2;i<=n-1;i++) 76 { 77 if(a[i]=='X'&&a[i+1]=='X'&&a[i-1]=='.') d[i-1]=1; 78 if(a[i]=='X'&&a[i-1]=='X'&&a[i+1]=='.') d[i+1]=1; 79 if(a[i]=='.'&&a[i-1]=='X'&&a[i+1]=='X') d[i]=1; 80 } 81 for(int i=1;i<=n;i++) b[i]=0; 82 for(int i=1;i<=n;i++) 83 if(a[i]=='X') 84 for(int j=-2;j<=2;j++) 85 if(i+j>0&&i+j<=n) b[i+j]=1; 86 int ans=0; 87 int s=0; 88 for(int i=1;i<=n;i++) 89 if(b[i]==0) s++; 90 else if(s) 91 { 92 ans^=g[s]; 93 s=0; 94 } 95 if(s) ans^=g[s]; 96 s=0; 97 for(int i=1;i<=n;i++) s+=d[i]; 98 if(ans||s) 99 { 100 printf("WINNING "); 101 int m=0; 102 for(int i=1;i<=n;i++) 103 if(a[i]=='.'&&isok(i)) d[i]=1; 104 for(int i=1;i<=n;i++) 105 if(d[i]) c[++m]=i; 106 for(int i=1;i<=m-1;i++) printf("%d ",c[i]); 107 printf("%d ",c[m]); 108 } 109 else 110 { 111 printf("LOSING "); 112 printf(" "); 113 } 114 } 115 return 0; 116 } 117