1. 程式人生 > >[BZOJ 1874] [BeiJing2009 WinterCamp] 取石子游戲

[BZOJ 1874] [BeiJing2009 WinterCamp] 取石子游戲

Description

每個人每次可以從一堆石子中取出若干個石子,每次取石子的個數有限制,誰不能取石子時就會輸掉遊戲。請你求出是否有先手必勝策略,如果有,第一步如何取石子。

Solution

當各堆的 \(SG\) 函式的異或和不為 \(0\) 時為必勝態,證明如下

Code

#include <cstdio>

int n, m, ans, a[15], b[15], sg[1005], f[15];

void getsg() {
    for (int i = 1; i <= 1000; ++i) {
        for (int j = 1; j <= m; ++j)
            if (i - b[j] >= 0) f[sg[i-b[j]]] = i;
        for (int j = 0; j <= 10; ++j)
            if (f[j] != i) { sg[i] = j; break; }
    }
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    scanf("%d", &m);
    for (int i = 1; i <= m; ++i) scanf("%d", &b[i]);
    getsg();
    for (int i = 1; i <= n; ++i) ans ^= sg[a[i]];
    if (!ans) puts("NO");
    else {
        puts("YES");
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j)
                if ((ans ^ sg[a[i]] ^ sg[a[i]-b[j]]) == 0) {
                    printf("%d %d\n", i, b[j]); return 0;
                }
    }
    return 0;
}