hdu 3980 Paint Chain 组合游戏 SG函数

题目链接

题意

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

思路

参考

转化

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

SG函数计算

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

\(x\lt m\)

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

\(x\geq 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;
}

posted @ 2017-10-18 09:29  救命怀  阅读(241)  评论(0编辑  收藏  举报