hdu 3980 Paint Chain 组合游戏 SG函数

题目链接

题意

有一个(n)个珠子的环,两人轮流给环上的珠子涂色。规定每次涂色必须涂连续的(m)颗珠子,无法继续操作的人输。问先手能否赢。

思路

参考

转化

第一个人取完之后就变成了一条,现只需要考虑这条链上的操作即可。

SG函数计算

考虑在一个链上涂连续的(m)颗珠子这个问题的子问题,记当前有(x)颗珠子

(xlt m)

显然已经无法涂了,故(sg(x)=0).

(xgeq m)

设左边有(i)颗珠子,则右边有((m-i))颗珠子。则该子问题的(sg)值为(sg(i)oplus sg(m-i)).

枚举所有子问题,计算(mex{sg(i)oplus sg(m-i)}).

Code

#include <bits/stdc++.h>
#define maxn 1010
using namespace std;
typedef long long LL;
int f[maxn], n, m;
bool vis[maxn][maxn], calc[maxn];
int fun(int x) {
    if (calc[x]) return f[x];
    calc[x] = true;
    if (x < m) return f[x] = 0;
    for (int i = 0; i <= x-m; ++i) vis[x][fun(i) ^ fun(x-m-i)] = true;
    int ret;
    for (int i = 0; i <= x; ++i) if (!vis[x][i]) { ret = i; break; }
    return f[x] = ret;
}
int kas;
void work() {
    scanf("%d%d", &n, &m);
    memset(f, 0, sizeof(f));
    memset(calc, 0, sizeof(calc));
    memset(vis, 0, sizeof(vis));
    printf("Case #%d: ", ++kas);
    if (n < m) { puts("abcdxyzk"); return; }
    if (!fun(n-m)) puts("aekdycoin");
    else puts("abcdxyzk");
}
int main() {
    int T;
    scanf("%d", &T);
    while (T--) work();
    return 0;
}

原文地址:https://www.cnblogs.com/kkkkahlua/p/7685110.html