[HNOI2007]分裂游戏 题解

中考+研学+放假 7 天,历经 18 天狂暴颓废后第一次碰 OI 的第一道题

SG 定理

Statement

给定 \(n(\le 21)\) 堆石头,每次可以选择一个堆,减去其中一个,然后使得两个编号所选择堆分别增加一个石头。

轮流操作,不能操作者输

求必胜方案数和字典序最小的第一步方案

Solution

naive 想法:

前 30 min 经典读错题,没有看到 \(i<j\le k\) 的限制。

然后也很蠢,想到这个游戏可能会无限进行下去(无限? \(\to\) 莫名其妙想到说,哈,那肯定是形成了一个环

乱 gb 想了一下如何在有向有环图中做 SG ,发现不太刑

仔细想想发现石子总和肯定是不断增加的,所以不存在环,只能是说无限长的链

那么干脆约定一下不能有这种反哺的情况,也就是默认反哺会进入一个必胜态

然后回头一看,很好,经典读错题,没事,太久没碰 OI 了,可以理解

(但是现在不能理解的是为什么这么久都不碰 OI ,也许现在正是考验我快速恢复能力的时候)

然后发现这个状态数吓人,模拟之后发现不会处理

正解:参考 lhm 的题解

仔细分析整个过程,考虑使用 SG 定理分解游戏

考虑每一个单独的石子颠沛流离最终到达位置 n 的过程,产生了无数的子子孙孙

我们可以直接认为对这些子子孙孙进行的操作依旧是对原来放置在 x 位置的石头的博弈,容易发现每一颗石头的博弈过程是相互独立的

所以我们直接设 \(sg[x]\) 表示在位置 x 的一个石头的博弈状态即可

容易发现可以对原问题中每一个位置的石头数量 \(\mod 2\)

SG 直接 \(O(n^3)\) 即可

Code

#include<bits/stdc++.h>
using namespace std;
const int N = 25;

char buf[1<<23],*p1=buf,*p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
int read(){
    int s=0,w=1; char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
    while(isdigit(ch))s=s*10+(ch^48),ch=getchar();
    return s*w;
}

int sg[N],a[N];
int T,n,ans,cnt,fg;

int dfs(int n){
    if(sg[n]!=-1)return sg[n];
    bool vis[5005]={0};
    for(int i=1;i<n;++i)
        for(int j=1;j<=i;++j)
            vis[dfs(i)^dfs(j)]=1;
    for(int i=0;i<5005;++i)if(!vis[i])
        return sg[n]=i;
}

signed main(){
    memset(sg,-1,sizeof(sg));
    sg[1]=0,dfs(22),T=read();
    while(T--){
        n=read(),ans=cnt=fg=0;
        for(int i=1;i<=n;++i){
            a[i]=read();
            if(a[i]%2)ans^=sg[n-i+1];
        }
        if(!ans){
            puts("-1 -1 -1\n0");
            continue;
        }
        for(int i=1;i<=n;++i)if(a[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])==0){
                    cnt++;
                    if(!fg)
                        printf("%d %d %d\n",i-1,j-1,k-1),fg=1;
                }
        printf("%d\n",cnt);
    }
    return 0;
}

posted @ 2022-06-26 21:56  _Famiglistimo  阅读(33)  评论(0编辑  收藏  举报