https://www.luogu.org/problemnew/show/P2148
给出n对(a, b)石子堆,每次可以选择一堆去掉后将另一堆分元素到这堆,每次操作后个堆数目>0
即(a, b) -> {(c, d) | c + d = a | c + d = b}
根据分析打表,预处理每个a的c + d的sg
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 10, maxm = maxn + 1;
typedef bitset<maxm> B;
B s[maxm];
int ans[maxn][maxn];
int sg_mex(B b) {
register int i = 0;
while(b[i]) ++i;
return i;
}
int main()
{
//(a, b)的下一个状态为{(c, d) | c + d = a}
//枚举每个a下的c + d = a时的sg值
for(register int i = 2; i <= maxn; i++) {
for(register int j = 1, k = i - 1; k; j++, k--) {
s[i].set(ans[j][k] = sg_mex(s[j] | s[k]));
}
}
for(register int i = 0; i < maxn; i++) printf("%3d", i);
printf("\n");
for(register int i = 1; i < maxn; i++) {
printf("%2d:", i);
for(register int j = 1; i + j <= maxn; j++) printf("%3d", ans[i][j]);
printf("\n");
}
for(register int i = 1; i <= maxn; i++) {
printf("%2d:Sg%d ", i, sg_mex(s[i]));
cout << s[i] << endl;
}
}
得出每个sg值为sg(a) | sg(b)后从后取连续1的数量,求个sg异或和
1:SG0 00000000000
2:SG1 00000000001
3:SG0 00000000010
4:SG2 00000000011
5:SG0 00000000100
6:SG1 00000000101
7:SG0 00000000110
8:SG3 00000000111
9:SG0 00000001000
10:SG1 00000001001
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int n, ans = 0;
scanf("%d", &n);
for (register int i = 0; i < n; i += 2)
{
int a, b, cnt = 0;
scanf("%d%d", &a, &b);
a--, b--;
a |= b;
while(a & 1)
cnt++, a >>= 1;
ans ^= cnt;
}
if(ans) printf("YES\n");
else printf("NO\n");
}
}