1. 程式人生 > >[BZOJ1188/Luogu3185][HNOI2007]分裂遊戲

[BZOJ1188/Luogu3185][HNOI2007]分裂遊戲

題目連結:

BZOJ1188

Luogu3185

博弈論。

首先,每一堆石子都是互相獨立,不影響的,那麼就只需求解每一堆的\(SG\)函式\(Xor\)即可。

再想,對於每一堆石子,裡面的每一個石頭都是互相獨立的,那麼就只需求解一個石子的\(SG\)函式,再用\(p_i\)\(Xor\)起來就得到了答案。

那麼如果是奇數不變,偶數個則為\(0\)

對於一個石子的\(SG\)函式暴力求即可。

妙啊喵啊

時間複雜度 \(O(Tn^3)\)

#include <cstdio>
#include <cstring>

int t,n,p[25],SG[25];
bool Bus[505];

int main()
{
    for(scanf("%d",&t);t--;)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;++i)scanf("%d",&p[i]);//這裡用1~n編號
        for(int i=n;i>=1;--i)
        {
            memset(Bus,0,sizeof Bus);
            for(int j=i+1;j<=n;++j)
                for(int k=j;k<=n;++k)
                    Bus[SG[j]^SG[k]]=true;//後繼狀態mex
            for(int j=0;j<=500;++j)
                if(!Bus[j])
                    SG[i]=j,j=500;
        }
        int TSG=0,p1=0,p2=0,p3=0,Cnt=0;
        for(int i=1;i<=n;++i)
            if(p[i]&1)
                TSG^=SG[i];//是奇數,只需xor一次
        if(TSG)
            for(int i=1;i<n;++i)
                for(int j=i+1;j<=n;++j)
                    for(int k=j;k<=n;++k)
                        if(!(TSG^SG[i]^SG[j]^SG[k]))//能使Xor和變為0(必敗)
                        {
                            ++Cnt;
                            if(!p1)p1=i,p2=j,p3=k;
                        }
        printf("%d %d %d\n%d\n",p1-1,p2-1,p3-1,Cnt);
    }
    return 0;
}