Official

K - Domino in Tetromino 2 Editorial by sounansya


この問題はゲームの温度という概念を用いることで解くことができます。

組合せゲームの温度とは、直感的にはその局面に対して今すぐ着手する価値がどれくらいあるかを表す数値です。

まず、局面 \(G\) の左終局値 \(L(G)\) と右終局値 \(R(G)\) を定義します。\(G\) が数 \(x\) に等しい場合は \(L(G)=R(G)=x\) とし、そうでない場合は \(\displaystyle L(G)=\max_{G^{\mathcal L}}R(G^{\mathcal L}), R(G)=\min_{G^{\mathcal R}}L(G^{\mathcal R}) \) と再帰的に定義します。ここで、\(G^{\mathcal L},G^{\mathcal R}\) はそれぞれ \(G\) の左選択肢・右選択肢を表します。

次に、局面 \(G\) と数 \(t\geq 0\) に対し、\(G\) を \(t\) だけ冷却した局面 \(G_t\) を定義します。数は冷却しても同じ数とし、その支柱値はその数自身、温度は \(0\) とします。

\(G\) が数でない場合は、各選択肢の冷却を用いて、補助的な局面 \(\widetilde{G}_t= \left\{ (G^{\mathcal L})_t-t \;\middle|\; (G^{\mathcal R})_t+t \right\} \) を作ります。\(\widetilde G_t\) の左終局値と右終局値が初めて一致する \(t\) を \(G\) の温度 \(T(G)\)、そのときの共通の値を支柱値 \(M(G)\) とします。有限のゲームでは、このような \(t\) が存在します。そして、実際の冷却を

\[ G_t= \begin{cases} \widetilde G_t,&0\leq t\leq T(G),\\ M(G),&t>T(G) \end{cases} \]

と定義します。つまり、温度を超えた後は支柱値に固定します。なお、左終局値と右終局値が一致しても、局面自体が数に等しいとは限らないため、\(t=T(G)\) では \(G_t=M(G)\) とは限りません。

実は、各成分のゲームの値が数、\(*\)、または数 \(u>v\) を選択肢にもつ \(\{u\mid v\}\) という形であるような直和では、正の温度の成分が残っている間、温度が最大の成分に着手する最善戦略が存在します。その後は、数の成分より \(*\) に優先して着手すればよいです。

各テトロミノとそのゲームの値、温度はそれぞれ以下のようになります:

種類  ゲームの値  温度
A \(\qquad -2 \qquad\) \(\qquad 0 \qquad\)
B \(\qquad 2 \qquad\) \(\qquad 0 \qquad\)
C \(\qquad -\frac{1}{2} \qquad\) \(\qquad 0 \qquad\)
D \(\qquad \frac{1}{2} \qquad\) \(\qquad 0 \qquad\)
E \(\qquad * \qquad\) \(\qquad 0 \qquad\)
F \(\qquad \left\{0 \mid -1\right\} \qquad\) \(\qquad \frac{1}{2} \qquad\)
G \(\qquad \left\{1 \mid 0\right\} \qquad\) \(\qquad \frac{1}{2} \qquad\)
H \(\qquad \left\{1 \mid -1\right\} \qquad\) \(\qquad 1 \qquad\)

したがって、\(H \to F, G \to E \to A,B,C,D\) の順に互いが着手していく状況を順にシミュレーションしていけば良いです。

実装例(Python3)

import sys

input = sys.stdin.readline
for _ in range(int(input())):
    a, b, c, d, e, f, g, h = map(int, input().split())
    x = 2 * (b - a) + (d - c) / 2
    Alice_turn = True
    if h % 2 == 1:
        x += 1
        Alice_turn = False
    if f > g:
        x -= (f - g) // 2
        if (f - g) % 2 == 1:
            if not Alice_turn:
                x -= 1
            Alice_turn ^= True
    if f < g:
        x += (g - f) // 2
        if (g - f) % 2 == 1:
            if Alice_turn:
                x += 1
            Alice_turn ^= True
    if x > 0:
        print("Alice")
        continue
    if x < 0:
        print("Bob")
        continue
    Alice_turn ^= e % 2 == 1
    print("Bob" if Alice_turn else "Alice")

参考:安福智明・坂井公・末續鴻輝『組合せゲーム理論の世界 ―数学で解き明かす必勝法―』共立出版, 2024.