問題
正の整数の組が $N$ 個あり、$i$ 個目は $(a_i,b_i)$ である。整数 $K$ が与えられる。2 人が交互に次の手を指す。
- 両方とも正の組を 1 つ選び、大きい方から小さい方の $k$ 倍($1\le k\le K$)を引く(結果は 0 以上)。2 つが等しいときはどちらから引いてもよい(結果は同じ)
- 片方が 0 になった組では、もう手が指せない
手が指せないプレイヤーの負けである。両者が最善を尽くすとき、先手が勝つなら First、後手が勝つなら Second を 1 行目に出力せよ。2 行目には、先手の勝ちにつながる最初の手の数を出力せよ(手は「どの組を、どの組に変えるか」で区別する。後手勝ちなら 0)。
入力形式
N K
a_1 b_1
...
a_N b_N
制約
| # | 制約 |
|---|---|
| 1 | $1\le N\le2\times10^5$ |
| 2 | $1\le K\le10^{18}$ |
| 3 | $1\le a_i,b_i\le10^{18}$ |
入出力例
入力例1
2 1
5 2
4 4出力例1
First
2($K=1$ は「1 回ずつ引く」ゲーム。$g(5,2)=0$、$g(4,4)=1$ で XOR は 1。制限なし(Day177-Q3)では同じ入力が後手勝ちだった)
入力例2
3 2
10 3
7 5
100 1出力例2
First
3($g(10,3)=0$、$g(7,5)=0$、$g(100,1)=1$。勝ち手は 3 組すべてに 1 つずつある。$(10,3)$ は $g=0$ なのに、3 の 2 倍を引いて値 1 の局面 $(4,3)$ へ動ける(1 倍を引いた $(7,3)$ は値 2)。Nim の流儀で「$t<g_i$ の組」だけを数えると 1 になって誤る)
入力例3
2 1000000000000000000
5 2
4 4出力例3
Second
0($K$ がすべての商より大きければ制限なしと同じ。Day177-Q3 の入力例 2 と同じ答え。3 例とも全状態の Grundy 数による全探索と一致)
背景と出典
- 制限なしのユークリッドゲーム(Cole–Davie 1969 と記憶、未確認)と、その Grundy 数を互除法の商から畳む方法は Day177-Q3 で扱った
- 「引ける倍数に上限がある」版の文献は、私は知らない(本セッションでは文献を探していない)。本問の周期性と式は本セッションで導き、$K=1..8$、$a,b<250$ の全 496008 組で全探索と一致することを確かめた
- 1 つの山から「1〜$K$ 個取る」引き算ゲームの Grundy 数が $n\bmod(K+1)$ になるのは有名な事実で、本問の鎖はその「先頭に値 $x$ が 1 つ置かれている」版にあたる
- 本問の問題文・制約・入力例は自作
概念図
ヒント(クリックで段階的に開示)
ヒント1(方向性)
$a\ge b$、$a=qb+r$($0\le r<b$)とする。$(a,b)$ から行けるのは $((q-k)b+r,\ b)$($1\le k\le\min(K,q)$)。$h_j=g(r+jb,\ b)$($j\ge1$)、$h_0=g(b,r)=:x$ と置くと、$h_j$ は直前 $\min(K,j)$ 個の $h$ の mex になる。$x\le K$ に注意(どの局面も行き先は $K$ 個以下なので、値は $K$ 以下)。
ヒント2(アプローチ)
- $1\le j\le K$ では窓が先頭まで届くので、制限なしと同じく $h_j=j-1$($j\le x$)、$h_j=j$($j>x$)
- 連続する $K+1$ 個の値はどの 2 つも 1 手でつながっているので互いに異なり、しかも全部 $K$ 以下。つまり $\{0,\dots,K\}$ の並べ替え。すると $h_j$ は窓に無い唯一の値、すなわち $h_{j-K-1}$ と等しい
ヒント3(誘導)
- $g(qb+r,b)=h_{q\bmod(K+1)}$。余り $j=0$ なら $x$、$1\le j\le x$ なら $j-1$、$j>x$ なら $j$
- 互除法の商の列を後ろから畳む(Day177-Q3 と同じ骨組みで、$q$ を $q\bmod(K+1)$ に置き換えるだけ)
- 勝ち手: $t=G\oplus g_i$。$q\le K$ なら制限なしと同じ判定。$q>K$ なら行き先は連続 $K$ 個の窓で、$\{0..K\}$ から $g_i$ を除いた全部の値がちょうど 1 回ずつ現れる。だから $t\le K$ なら 1 手
模範解答 (Python)
模範解答を表示する(まず自力で解いてから)
import sys
def main():
data = sys.stdin.buffer.read().split()
n, K = int(data[0]), int(data[1])
P = K + 1 # 鎖の値の周期
gs = []
info = []
for i in range(n):
a = int(data[2 + 2 * i])
b = int(data[3 + 2 * i])
if a < b:
a, b = b, a
qs = []
while b:
qs.append(a // b)
a, b = b, a % b
x = 0 # (d, 0) は終局で値 0
for q in reversed(qs[1:]):
j = q % P # h_q = h_{q mod (K+1)}
x = x if j == 0 else (j - 1 if j <= x else j)
q = qs[0]
j = q % P
g = x if j == 0 else (j - 1 if j <= x else j)
gs.append(g)
info.append((q, x))
G = 0
for g in gs:
G ^= g
if G == 0:
print("Second")
print(0)
return
cnt = 0
for g, (q, x) in zip(gs, info):
t = G ^ g
if q > K: # 窓は連続 K 個 → {0..K} から g を除いた全部
cnt += t <= K
elif t == x: # q <= K: 制限なしと同じ鎖 h_0..h_{q-1}
cnt += 1
elif t < x:
cnt += t <= q - 2
else:
cnt += t <= q - 1
print("First")
print(cnt)
main()
計算量: 1 組あたり互除法の段数 $O(\log\max(a,b))$。$N=2\times10^5$ で乱数($K$ も乱数)0.70 s、$K=3$ でも 0.70 s、全組が隣り合うフィボナッチ数(商がすべて 1 の最悪ケース)で 1.55 s、いずれも約 70 MB(Python 3.14.8、Apple M5 Pro、負荷平均 15〜20 での実測、起動込み)。
Step-by-Step 解説
1行き先は鎖の「窓」
$(qb+r,b)$ から $b$ の $k$ 倍を引くと $((q-k)b+r,\ b)$。$k\le\min(K,q)$ なので、鎖の添字でいえば $j=q$ から $[\max(0,q-K),\ q-1]$ の範囲へ動ける。$j=0$ の $(r,b)$ だけは大小が入れ替わり、別の組 $(b,r)$ の世界に入る。制限なしとの違いは、遠くの $j$(特に $h_0=x$)へ一気に飛べなくなることだけ。
2先頭 $K+1$ 個
$1\le j\le K$ のときは窓が $h_0$ まで届くので、制限なしと同じ「$x$ を 1 つ飛ばした列」$0,1,\dots,x-1,x+1,\dots$ になる。$h_0..h_K$ はちょうど $\{0,\dots,K\}$ の並べ替え。
3周期 $K+1$
$j>K$ では、$h_j$ は直前 $K$ 個(互いに異なり、$K$ 以下)の mex。直前 $K$ 個が $\{0..K\}$ から 1 つだけ欠けた集合なら mex はその欠けた値で、それは $h_{j-K-1}$。帰納的に、連続 $K+1$ 個はいつも並べ替えで、$h_j=h_{j-K-1}$。
$$g(qb+r,\,b)=h_{q\bmod(K+1)}=\begin{cases}x&(q\equiv0)\\ j-1&(1\le j\le x)\\ j&(j>x)\end{cases}\qquad j=q\bmod(K+1)$$
4和と勝ち手の数
Sprague–Grundy の定理で和の値は XOR。組 $i$ を値 $t=G\oplus g_i$ に変える手の数を数える。
- $q\le K$: 窓は鎖全体 $h_0..h_{q-1}$ で、Day177-Q3 と同じ場合分け
- $q>K$: 窓は連続 $K$ 個。$h_{q-K}..h_q$ の $K+1$ 個が並べ替えなので、窓には $\{0..K\}\setminus\{g_i\}$ がちょうど 1 回ずつ現れる。$G\ne0$ なら $t\ne g_i$ なので、$t\le K$ のとき 1 手
$q>K$ の組では $g_i$ より大きい値へも動ける。これが Nim の流儀($t<g_i$ の組だけ数える)が外れる理由。
5大きな数
$K$ と $q$ は $10^{18}$ まで。値は $K$ 以下に収まるが、$K$ 自体が大きいので Python の整数でそのまま XOR する。$K\ge$ すべての商なら $q\bmod(K+1)=q$ で、Day177-Q3 の式に戻る(入力例 3)。
迷った他案と採らなかった理由
| 案 | 計算量 | 採否 | 理由 |
|---|---|---|---|
| Grundy 数の表(メモ化) | $O(A^2K)$ | 検算用のみ | $10^{18}$ では不可能 |
| 制限なしの式(Day177-Q3)をそのまま使う | $O(\log)$ | 不採用(誤り) | 2000 個の和で 479 個の勝敗を誤る(実測) |
| 周期を $K$ と取り違えて $q\bmod K$ で畳む | $O(\log)$ | 不採用(誤り) | 681/2000 誤り(実測)。引き算ゲーム「1〜$K$ 個取る」の周期は $K+1$ |
| 制限なしの値を $K$ で頭打ち $\min(g,K)$ にする | $O(\log)$ | 不採用(誤り) | 526/2000 誤り(実測)。値は頭打ちではなく巡回する |
| 勝ち手を「$t<g_i$ の組の数」で数える | $O(N)$ | 不採用(誤り) | 先手勝ち 1335 個中 525 個で数が合わない(実測)。$q>K$ の組では $t>g_i$ にも行ける |
| 鎖の周期性で畳む(本解) | $O(N\log V)$ | 採用 | 0.70〜1.55 s |
前提が変わったら
- 引く倍数の下限もある($L\le k\le K$)なら、窓が $[j-K,\ j-L]$ になり、連続する値が互いに異なるとは限らない。周期は $L+K$ 程度になりそうだが、本セッションでは調べていない
- 組ごとに $K_i$ が違うなら、式の $K$ を組ごとに替えるだけで同じく解ける(周期性の議論は組の中で閉じている)
- misère(最後に指した人の負け)なら XOR が使えない。Day177-Q3 と同じく未調査
よくあるミス
| ミス | 原因 | 正しい書き方 |
|---|---|---|
| $q\bmod K$ で畳む | 「$K$ 倍まで」から周期 $K$ と思う | 1〜$K$ 個取る引き算ゲームと同じく周期 $K+1$ |
| 余り 0 を 0 とする | $h_0$ が $x$ であることを忘れる | 余り 0 なら $x$(大小が入れ替わった先の値) |
| $q>K$ でも制限なしの勝ち手判定を使う | 窓が鎖全体だと思い込む | $q>K$ なら「$t\le K$ なら 1 手」 |
| 値が $K$ 以下だから $K$ ビットの配列で持つ | $K$ が $10^{18}$ まであることを見落とす | 値は整数のまま扱う |
| $a=b$ を別扱いし忘れる | $q=1,r=0$ を特別と思う | $r=0$ なら $x=0$、$j=1$ で $g=1$。式のままで正しい |
次のステップ
- 発展1: 下限つき($L\le k\le K$)の版で鎖の値の列を全探索で調べ、周期と前周期を求める
- 発展2: 「勝ち手を 1 つ出力」に変え、$q>K$ の組で値 $t$ を持つ $j$ を $O(1)$ で逆算する($j\equiv$ 値の位置 $\pmod{K+1}$ を窓の中から選ぶ)
- 発展3: Day177-Q3 と合わせ、組ごとに $K_i$ が違う和を作って検算する
検証ログ(本セッションで実行した数値)
- 1 組の Grundy 数(実測): $K=1..8$、$1\le a,b<250$ の全 496008 組で、メモ化 mex の全探索と周期式が全件一致
- 和と勝ち手の数(実測): $K=1..6$、1〜4 組・各値 120 以下の 2000 個で、勝敗と勝ち手の数(全手を列挙して XOR が 0 になる手を数えた)が全件一致(先手勝ち 1335 個)
- 誤った方法(実測、同じ 2000 個): 制限なしの式 479、$q\bmod K$ 681、$\min(g,K)$ 526 で勝敗を誤る。Nim 流の勝ち手の数は 1335 個中 525 個で不一致
- 時間(実測、起動込み、$N=2\times10^5$、負荷平均 15〜20): 乱数 0.70 s、$K=3$ 0.70 s、$(679891637638612258,420196140727489673)$ を全組・$K=2$ で 1.55 s。最大常駐 約 70 MB
- 扱っていない範囲: 文献の確認、下限つきの版、misère 版