bzoj 1188 SG函数

  首先我们可以把一个石子看成一个单独的游戏,那么我们可以发现所有位置的石子至于奇偶有关,因为某一个人操作其中的一个石子,我们可以用相同的石子做相同的操作,所以我们只需要保留下所有位置的01,那么对于每个位置的sg函数值,我们需要枚举之后所有可能放的情况就可以了。然后我们就可以判断是否先手必胜,然后对于方案,我们就枚举取哪一个向哪儿放,求出来之后的sg值,要是先手必败的话,这个方案就是先手必胜的,累加答案就好了。

/**************************************************************

    Problem: 1188

    User: BLADEVIL

    Language: C++

    Result: Accepted

    Time:0 ms

    Memory:804 kb

****************************************************************/

 

//By BLADEVIL

#include <cstdio>

#include <cstring>

#define maxn 30

 

using namespace std;

 

int flag[100],sg[maxn],a[maxn];

 

void prepare()

{

    for (int i=1;i<=25;i++)

    {

        int j;

        memset(flag,0,sizeof flag);

        for (j=1;j<i;j++)

            for (int k=1;k<i;k++) flag[sg[j]^sg[k]]=1;

        for (j=0;flag[j];j++);

        sg[i]=j;

    }

}

 

void solve()

{

    int n;

    scanf("%d",&n);

    for (int i=1;i<=n;i++) scanf("%d",&a[i]);    

    int ans=0;

    for (int i=1;i<=n;i++) if (a[i]&1) ans^=sg[n-i+1];

    if (!ans) {printf("-1 -1 -1\n0\n");return;}

    int ans1,ans2,ans3,kind;

    ans1=ans2=ans3=kind=0;

    for (int i=1;i<=n;i++)

        for (int j=i+1;j<=n;j++)

            for (int k=j;k<=n;k++) 

                if (!(ans^sg[n-i+1]^sg[n-j+1]^sg[n-k+1])) 

                    if (!kind++) ans1=i,ans2=j,ans3=k;

    printf("%d %d %d\n%d\n",ans1-1,ans2-1,ans3-1,kind);

}

 

int main()

{

    prepare();

    int task;

    scanf("%d",&task);

    while (task--) solve();

    return 0;

}

 

你可能感兴趣的:(ZOJ)