luogu P3185 [HNOI2007]分裂游戏

https://www.luogu.com.cn/problem/P3185

把每个碗里的状态全部记下来显然是不现实的,分析一下发现可以把每个豆子看作一个独立的游戏

然后就变成相当于要将\(i\)移动到\(n\),这个反过来跑个\(SG\)函数即可

按照\(SG\)函数的定理做就好了

好像就是\(Multi-SG\)

具体可以参考代码

code;

#include<bits/stdc++.h>
#define N 200050
using namespace std;
int n, t, a[N], sg[N], vis[N];
void solve() {
    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];
    if(!ans) printf("-1 -1 -1\n0\n");
    else {
        int gs = 0, ansi = 0, ansj = 0, ansk = 0;
        for(int i = 1; i <= n; i ++)
            for(int j = i + 1; j <= n; j ++)
                for(int k = j; k <= n; k ++) {
                    if((sg[n - i] ^ sg[n - j] ^ sg[n - k] ^ ans) == 0) {//判断先选了i,j,k后剩下的是不是必败态
                        gs ++;
                        if(gs == 1) ansi = i, ansj = j, ansk = k;
                    }
                }
        printf("%d %d %d\n%d\n", ansi - 1, ansj - 1, ansk - 1, gs);
    }
}
int main() {
   // freopen("a.out","w",stdout);
    for(int i = 1; i <= 21; i ++) { // 预处理SG函数
        for(int j = 0; j <= 114514; j ++) vis[j] = 0;
        for(int j = 0; j < i; j ++)
            for(int k = j; k < i; k ++)
                vis[sg[j] ^ sg[k]] = 1;
        for(int j = 0; j <= 114514; j ++) 
            if(!vis[j]) {
                sg[i] = j;
                break;
            }
    }

    scanf("%d", &t);
    while(t --) solve();
    return 0;
}
posted @ 2022-02-16 15:34  lahlah  阅读(34)  评论(0)    收藏  举报