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;
}

 

posted on 2014-04-01 13:11  BLADEVIL  阅读(408)  评论(0编辑  收藏  举报