题目链接
题意
有一个(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;
}