(博弈/sg打表)E&D

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

猜你喜欢

转载自blog.csdn.net/weixin_40588429/article/details/83902145