1. 程式人生 > 其它 >AtCoder ABC172 F - Unfair Nim 題解

AtCoder ABC172 F - Unfair Nim 題解

博弈論的題目一定就是 DP 嗎?

Warning:
所有更新在原文釋出,在原文食用體驗更佳!

題意

題目連結:https://atcoder.jp/contests/abc172/tasks/abc172_f

\(n\) 堆石子,第 \(i\) 堆有 \(a_i\) 個,兩人輪流選擇一堆取石子,至少取一個,至多把這堆取完。
後手開掛了,可以在開局前將第一堆石子中拿若干個石子到第二堆(不能把第一堆拿完),問最少拿多少石子到第二堆才能使後手必勝。
\(2 \le n \le 300\), \(1 \le a_i \le 10^{12}\)

思路

前置芝士

Nim 遊戲
Nim 遊戲解法
Nim 遊戲解法證明

問題轉化

\(A = a_1\)

\(B = a_2\)\(C = \oplus_{i=3}^n a_i\)
則原問題轉化為求最大的 \(A'\)\(B'\) 使得 \(A' \oplus B' \oplus C = 0\)\(A' + B' = A + B\)

大體確定

\(D = \frac{A' + B' - C}{2}\),不難發現 \(D = A' \operatorname{and} B'\)
我們可以按位考慮,對於每一位:

  • 如果 \(A' = B' = 0\),則 \(C = 0\),那麼 \(D = 0 = A' \operatorname{and} B'\)
  • 如果 \(A' = B' = 1\)
    ,則 \(C = 0\),那麼 \(D = 1 = A' \operatorname{and} B'\)
  • 如果 \(A'\), \(B'\) 一個為 \(0\),另一個為 \(1\),則 \(C = 1\),那麼 \(D = 0 = A' \operatorname{and} B'\)

又因為 \(D = \frac{A' + B' - C}{2} = \frac{A + B - C}{2}\),所以我們可以求出 \(D\)
而我們要求 \(A'\) 最大,所以 \(D = A' \operatorname{and} B'\) 應該都放到 \(A'\) 上。

細微調整

還是按位考慮。

對於每一位,如果 \(C = 1\)

,那麼 \(A'\), \(B'\) 中必有一個為 \(1\),如果將這一位的 \(1\) 加到 \(A'\) 上滿足題意(加上後 \(A' < A\))就加到 \(A'\) 上。

最後加一些特判(見程式碼)就完了。

程式碼

// 程式碼中的 a 是上面的 A'
#include <cstdio>

typedef long long LL;

int main() {
    int n;
    scanf("%d", &n);
    LL A = 0, B = 0, C = 0;
    scanf("%lld%lld", &A, &B);
    for(int i = 3; i <= n; i++) {
        LL x;
        scanf("%lld", &x);
        C ^= x;
    }
    LL D = (A + B - C) >> 1;
    if(((A + B - C) & 1) || D < 0 || D > A || D & C)
        { puts("-1"); return 0; }
    LL a = D;
    for(int i = 60; i >= 0; i--)
        if((C & (1LL << i)) && (a | (1LL << i)) <= A)
            a |= (1LL << i);
    printf("%lld\n", a == 0 ? -1LL : A - a);
    return 0;
}