题目大意:有一个'.'、'X'串,如今两人轮流把'.'改为'X',先连出三个连续的'X'的胜,求先手是否有必胜策略。若是有,输出全部可行的第一步。串长≤200,保证初始无三连'X'。ios
博弈题真有意思,也很久没有作过了,搞得我连SG函数的性质都记反了,真尬。ide
首先能够看出原本就有二连'X'的确定要选掉,并且确定是第一步选,就把直接获胜的判掉了。因此下面考虑的都是不能一步出解的。函数
不难分析出,在'X'的左右两格都不能放,因此原串被分割成了不少个不相交的区间,并且这些区间互不影响,这个就很显然是用博弈知识来解决了。spa
很明显一个区间的胜负态只与这个区间的长度有关,因此SG(x)表示长度为x的区间的SG函数值。code
首先能够推出SG(0)=0,SG(1)=SG(2)=SG(3)=1。(就是这里让我算了很久,mmp)blog
根据SG函数的定义,状态x的SG值应该是全部后继状态的集合的mex。get
因而大力找出全部后继状态(枚举此次改哪一个地方)+SG定理求出mex就能够了。打表发现串长不超过200时,SG值不到20,随便怎么搞就过去了。string
这个时候有没有解已经能够用SG定理知道了,但输出方案……it
反正串长只有那么点,直接暴力枚举答案,一样用SG定理判断便可。io
最后就是这题卡输出格式,丧心病狂,并且代码根本压不下来。
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <vector> #include <cstring> #include <queue> #include <complex> #include <stack> #define LL long long int #define dob double #define FILE "10561" using namespace std; const int N = 210; int n,vis[20],sg[N]; char S[N];bool os[N]; inline int gi(){ int x=0,res=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();} while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*res; } inline int prepare(){ sg[0]=0;sg[1]=sg[2]=sg[3]=1; for(int i=1;i<=200;++i){ memset(vis,0,sizeof(vis)); vis[sg[i-3]]=vis[sg[i-4]]=vis[sg[i-5]]=1; for(int j=1;j<=i-5-j;++j) vis[sg[j]^sg[i-5-j]]=1; for(int j=0;j<=200;++j) if(!vis[j]){sg[i]=j;break;} } return gi(); } inline bool Is(int x){ if(x<0 || x>n)return false; return S[x]=='X'; } inline bool canput(int x){ if(Is(x-2) || Is(x-1) || Is(x) || Is(x+1) || Is(x+2)) return false; return x<=n; } inline bool check(int ans=0){ for(int l=1,r=1;l<=n;l=++r) if(canput(l)){ for(;r<=n;++r) if(!canput(r+1))break; ans^=sg[r-l+1]; } return ans; } inline void solve(int flg=0){ scanf("%s",S+1);n=strlen(S+1); for(int i=3;i<=n;++i) if(Is(i-2)+Is(i-1)+Is(i)>=2) flg=1; if(flg){ printf("WINNING\n");flg=0; for(int i=1;i<=n;++i) if(!Is(i)) if((Is(i-2) && Is(i-1)) || (Is(i-1) && Is(i+1)) || (Is(i+1) && Is(i+2))){ if(flg)printf(" "); printf("%d",i);flg=1; } printf("\n");return; } if(!check()){printf("LOSING\n\n");return;} printf("WINNING\n");flg=0; for(int i=1;i<=n;++i) if(canput(i)){ S[i]='X'; if(!check()){ if(flg)printf(" "); printf("%d",i);flg=1; } S[i]='.'; } printf("\n"); } int main() { freopen(FILE".in","r",stdin); freopen(FILE".out","w",stdout); int Case=prepare();while(Case--)solve(); fclose(stdin);fclose(stdout); return 0; }