题目链接:http://lightoj.com/volume_showproblem.php?problem=1229
题意:一排n个位置,有些位置已经放上了字母X,剩下的是空的。两人轮流放置X在空的位置。放置后出现连续3个X的赢。问先手是否有必胜策略?若有,可以放在哪些地方?
思路:枚举每个空的位置作为先手放置X的位置,然后判断是否能赢。这样,就会出现一些连续的空闲位置,求这些空闲位置的SG和。
const int INF=2000000000;
const int N=10005;
int SG[N];
int C,num=0;
string s;
int DFS(int x)
{
if(x<0) return 0;
if(SG[x]!=-1) return SG[x];
int a[300]={0},i;
FOR1(i,x) a[DFS(i-3)^DFS(x-i-2)]=1;
for(i=0;a[i];i++);
return SG[x]=i;
}
int OK(int pos)
{
string s1=s;
int i,j,L=Len(s1);
if(s1[pos]=='X') return 0;
s1[pos]='X';
for(i=0;i+2<L;i++) if(s1[i]=='X'&&s1[i+1]=='X'&&s1[i+2]=='X')
{
return 1;
}
FOR0(i,L)
{
if(i+1<L&&s1[i]=='X'&&s1[i+1]=='X') return 0;
if(i+2<L&&s1[i]=='X'&&s1[i+2]=='X') return 0;
}
int ans=0,a=2,b=0,k;
FOR0(i,L) if(s1[i]=='X') k=i;
FOR0(i,L)
{
if(i>k) a=0;
if(s1[i]=='X')
{
b=2;
continue;
}
for(j=i;s1[j]=='.';j++);
ans^=DFS(j-i-a-b);
i=j-1;
}
return !ans;
}
int main()
{
clr(SG,-1);
RD(C);
while(C--)
{
vector<int> a;
int i;
RD(s);
FOR0(i,Len(s)) if(OK(i)) a.pb(i);
printf("Case %d: ",++num);
if(SZ(a)==0) puts("0");
else
{
FOR0(i,SZ(a)-1) printf("%d ",a[i]+1);
printf("%d\n",a[i]+1);
}
}
return 0;
}