LightOJ 1229 Treblecross(SG函数)

题目链接: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;

}

  

你可能感兴趣的:(OS)