题解:题目要求3个X不能相邻,会产生相邻的位置就成了禁区,则X会将其分成很多段,每一段只包含可以下的位置就是其后继状态,预处理出.数目的sg函数,最后将分段后的sg异或就是答案,合法位置就是选了当前位置后局势转变为先手必败
AC代码:
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#define ll long long
using namespace std;
const int maxn=10000;
char mp[205];
int fa[205],sg[205];
int y[205],s[205],s1[205];
int ans[205];
int getsg(int x){
memset(fa,-1,sizeof(fa));
for(int a=1;a<=x;a++){
int l=max(a-3,0);
int r=max(x-a-2,0);
fa[sg[l]^sg[r]]=1;
}
int ans1=0;
for(;;ans1++){
if(fa[ans1]!=1)
return ans1;
}
}
void init(){
sg[0]=0;
sg[1]=sg[2]=sg[3]=1;
for(int a=4;a<=200;a++)
sg[a]=getsg(a);
}
int get(int len,int t){
int z=0;
for(int a=0;a<len;a++){
if(mp[a]=='X'){
y[a]=t;
if(a+1<len)
y[a+1]=t;
if(a+2<len)
y[a+2]=t;
if(a-1>=0)
y[a-1]=t;
if(a-2>=0)
y[a-2]=t;
}
else{
if((a+1<=len&&a-1>=0&&mp[a+1]=='X'&&mp[a-1]=='X')||(a+1<=len&&a+2<=len&&mp[a+1]=='X'&&mp[a+2]=='X')||(a-1>=0&&a-2>=0&&mp[a-1]=='X'&&mp[a-2]=='X'))
ans[++z]=a+1;
}
}
return z;
}
void get1(int len,int t){
int num=0;
for(int a=len-1;a>=0;a--){
if(y[a]==t)
s[a]=s[a+1],num=0;
else{
num++;
s[a]=s[a+num]^sg[num];
}
}
s1[0]=0;
num=0;
for(int a=0;a<len;a++){
if(y[a]==t)
s1[a+1]=s1[a],num=0;
else{
num++;
s1[a+1]=s1[a-num+1]^sg[num];
}
}
}
int main( )
{
init();
s[0]=0;
int t,len;
scanf("%d",&t);
for(int t1=1;t1<=t;t1++){
scanf("%s",mp);
len=strlen(mp);
s[len]=0;
printf("Case %d:",t1);
int ju=get(len,t1);
if(ju!=0){
for(int a=1;a<=ju;a++)
printf(" %d",ans[a]);
printf("\n");
continue;
}
get1(len,t1);
for(int a=1;a<=len;a++){
int b=a-1;
if(y[b]==t1)
continue;
int sg1=0;
if(b-3>=0)
sg1^=s1[b-2];
if(b+2<len)
sg1^=s[b+3];
if(sg1==0){
printf(" %d",a);
//printf("\n%d %d %d %d\n",b-2,b+3,s1[b-2],s[b+3]);
ju=1;
}
}
if(!ju)
printf(" %d",ju);
printf("\n");
}
}