mayoko’s diary

プロコンとかいろいろ。

Codeforces Round #354 (Div. 2) E. The Last Fight Between Human and AI

問題

codeforces.com

A さんと B さんが N 次の多項式の係数を埋めるゲームをする(係数は実数ならなんでも良い)。

A さんの目的はこの多項式が x-k で割り切れるようにすることで, B さんはそれを阻止することが目的である。

B さんが先行ですでにいくつかの係数が埋められている。この後 A さんと B さんが最適に動いた場合, 勝者はどちらになるか?

解法

因数定理より, x-k で多項式が割り切れるというのは, f(k) = 0 となることです。

それを考えると, 最終ターンの人が 係数を適当に調整すれば必ず f(k) = 0 とすることができそうなので, (N+1) の偶奇で勝者が決まりそうです。

ただし, 例外が二つあります。

k = 0 の場合
この場合は, 0 次の係数(a[0] とする)以外は関係ないので, そこを先にいじれた人が勝ちです。
a[0] = 0 の時, A 君の勝ちです。
a[0] がまだ決まっていないとき, 次の手番の人が勝ちです。
a[0] != 0 の時, B 君の勝ちです。

すでにすべての係数が埋まっている場合
この場合は, すでに勝敗が決まっているので, どちらが勝ったのかを調べましょう。
ただ, f(k) を直接計算すると数が大きすぎて死ぬので, 50 個ほど乱数を発生させて, それらで割ったあまりがすべて 0 だったら f(k) = 0, と判定することにします。

const int MAXN = 100100;
const int CHECK = 50;
string a[MAXN];
std::random_device rnd;
ll mod[CHECK], p[CHECK], sum[CHECK];

bool solve() {
    int n, k;
    cin >> n >> k;
    int turn = 0;
    for (int i = 0; i <= n; i++) {
        cin >> a[i];
        if (a[i] == "?") turn++;
    }
    if (k == 0) {
        if (a[0] == "0") return true;
        if (a[0] == "?") return (n+1-turn)%2 == 1;
        return false;
    }
    if (turn == 0) {
        for (int i = 0; i < CHECK; i++) {
            mod[i] = 1000000000+rnd()%1000000;
            if (mod[i]%2==0) mod[i]++;
            p[i] = 1;
        }
        for (int i = 0; i <= n; i++) {
            ll num = 0;
            if (a[i][0] == '-') {
                for (int j = 1; j < a[i].size(); j++)
                    num = 10*num+(a[i][j]-'0');
                num *= -1;
            } else {
                for (char c : a[i]) {
                    num = 10*num+(c-'0');
                }
            }
            for (int j = 0; j < CHECK; j++) {
                sum[j] += p[j]*num%mod[j];
                sum[j] %= mod[j];
                (p[j] *= k) %= mod[j];
            }
        }
        for (int i = 0; i < CHECK; i++) {
            if (sum[i]) return false;
        }
        return true;
    }
    if ((n+1)%2==0) return true;
    return false;
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    if (solve()) cout << "Yes" << endl;
    else cout << "No" << endl;
    return 0;
}