P3185 [HNOI2007]分裂游戏

传送门

 

因为每个豆子都是互相独立的,所以各看成一个子博弈

他们之间的状态只和位置有关,因为每次操作都会多出一个豆子,相当于多一个子博弈

那就是 $multi-SG$ 模型了,数据很小,考虑直接求出每个状态的 $SG$ 值

根据 $multi-SG$ 的理论,设 $SG[i]$ 表示第 $i$ 个位置的 $SG$,那么有 $SG[i]=mex(SG[j]\ xor\ SG[k]),i<j<=k<=n$

然后枚举第一步怎么走,看看走完后总的 $SG$ 是不是 $0$ 就知道后手是不是必败了

当然如果把位置倒过来求 $SG$,就只要预处理一次 $SG$,因为那样 $SG$ 就与 $n$ 无关了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=27,M=1e6+7;
int n,a[N],SG[N],vis[233];
void pre()
{
    memset(vis,-1,sizeof(vis));
    memset(SG,0,sizeof(SG));
    for(int i=n-1;i>=0;i--)
    {
        for(int j=i+1;j<=n;j++)
            for(int k=j;k<=n;k++)
                vis[SG[j]^SG[k]]=i;
        while(vis[SG[i]]==i) SG[i]++;
    }
}
inline void solve(int ans)
{
    int cnt=0,a=0,b=0,c=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[i]^SG[j]^SG[k])==0)
                    if(!(cnt++)) a=i,b=j,c=k;
    printf("%d %d %d\n%d\n",a-1,b-1,c-1,cnt);
}
int main()
{
    int T=read();
    while(T--)
    {
        n=read(); pre(); int ans=0;
        for(int i=1;i<=n;i++) a[i]=read(),ans^=(a[i]&1 ? SG[i] : 0);
        if(!ans) printf("-1 -1 -1\n0\n");
        else solve(ans);
    }
    return 0;
}

 

posted @ 2019-08-28 09:06  LLTYYC  阅读(235)  评论(0编辑  收藏  举报