简答
2026-09-06 18:03:20
发布于:湖南
这是一道博弈论类型的题目,属于石子游戏变种,使用SG函数来处理。
首先理解游戏规则,只有石子数量大于等于给定阈值的堆才可以操作。操作的时候选定一堆,把它拆成若干堆,拆分要求尽可能平均,拆分之后每一堆的数量只有两种取值,拆分出来的结果是固定的。石子数量小于阈值的堆无法进行任何操作。
每一堆石子可以看作独立的游戏,整局游戏的胜负,由各个堆的SG值做异或运算得到。
解题的第一步,预处理出所有可能石子数量对应的SG值。
对于小于阈值的石子堆,无法操作,对应的SG值直接为零。
对于大于等于阈值的石子堆,枚举所有合法的拆分方式,得到拆分之后多个子堆的SG值,把子堆SG进行异或,收集全部结果,取mex就得到当前数量的SG值。
拆分的时候注意,选定拆分份数之后,拆分出来只会有两类大小的堆,统计两类堆各自的个数。如果某一类堆的数量是偶数,那么这部分的异或结果会抵消变成零,只需要看数量为奇数那一类对应的SG值,不需要把每一堆都逐个异或,以此节省时间。
处理每一组询问的时候,把这一组里每一堆石子对应的SG值全部异或起来。
如果最终异或结果不为零,先手可以获胜。如果异或结果等于零,后手可以获胜。
整体流程就是先预处理SG数组,之后每组数据直接查询各个堆的SG做异或,输出胜负结果。
#include <bits/stdc++.h>
using namespace std;
inline long long read() {
long long s = 0, f = 1; char ch;
while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
return s * f;
}
const int N = 105, M = 1e5 + 5;
int T, F, n;
int a[N], SG[M], vis[N];
int main() {
T = read(); F = read();
for(int i = F;i <= M - 5; i++) {
int r;
for(int j = 2;j <= i; j = r + 1) {
int t = i / j;
r = i / (i / j);
int flag;
if(j == r) flag = 1;
else flag = 2;
int num = 0, res = 0;
while(num < flag) {
num++;
res = 0;
if((i % j) & 1)
res ^= SG[t + 1];
if((j - i % j) & 1)
res ^= SG[t];
j++;
vis[res] = i;
}
}
for(int j = 0; ; j++){
if(vis[j] != i){
SG[i] = j; break;
}
}
}
while(T --> 0) {
n = read();
int res = 0;
for(int i = 1;i <= n; i++) {
a[i] = read();
res ^= SG[a[i]];
}
if(res == 0) printf("0 ");
else printf("1 ");
}
return 0;
}
这里空空如也








有帮助,赞一个