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