問題
正の整数の組が $N$ 個あり、$i$ 個目は $(a_i,b_i)$ である。整数 $L,K$ が与えられる。2 人が交互に次の手を指す。
- 両方とも正の組を 1 つ選び、大きい方から小さい方の $k$ 倍($L\le k\le K$)を引く(結果は 0 以上)。2 つが等しいときはどちらから引いてもよい(結果は同じ)
- 片方が 0 になった組、および大きい方が小さい方の $L$ 倍未満の組では、もう手が指せない
手が指せないプレイヤーの負けである。両者が最善を尽くすとき、先手が勝つなら First、後手が勝つなら Second を 1 行目に出力せよ。2 行目には、先手の勝ちにつながる最初の手の数を出力せよ(手は「どの組を、どの組に変えるか」で区別する。後手勝ちなら 0)。
入力形式
N L K
a_1 b_1
...
a_N b_N
制約
| # | 制約 |
|---|---|
| 1 | $1\le N\le2\times10^5$ |
| 2 | $1\le L\le K\le10^{18}$ |
| 3 | $1\le a_i,b_i\le10^{18}$ |
入出力例
入力例1
2 2 3
7 2
5 5出力例1
First
1($L=2,K=3$。$(5,5)$ は商が 1 で $L$ 未満なので手が無く値 0。$(7,2)$ は値 2。勝ち手は $7$ から $2\times2$ を引いて値 0 の $(3,2)$ にする 1 手だけ。$k=1$ は禁止なので $(5,2)$ には行けない)
入力例2
3 2 5
20 3
9 4
100 7出力例2
First
2(値は $3,0,2$ で XOR は 1。勝ち手は 2 つ)
入力例3
2 1 1000000000000000000
5 2
4 4出力例3
Second
0($L=1$ で $K$ がすべての商より大きければ制限なし。Day177-Q3・Day178-Q1 の入力例と同じ答え。3 例とも全状態の Grundy 数による全探索と一致)
背景と出典
- 上限 $K$ だけの版は Day178-Q1(周期 $K+1$)、制限なしの版は Day177-Q3 で扱った
- 1 つの山から「$L$〜$K$ 個取る」引き算ゲームの Grundy 数が $\lfloor (n\bmod(L+K))/L\rfloor$ になることは、私の記憶にある有名な事実(原典は本セッションで確認していない)。本問の鎖はその「先頭に別の値 $x$ が 1 つ置かれた」版
- 本問の周期式(先頭 $x$ による区画のずれ)は本セッションで実験から読み取り、$K\le40$ の全 $(L,x)$ の鎖 4323 本と、$K\le8$・$a,b<120$ の全局面 509796 組で全探索と一致することを確かめた。一般の証明は書いていない(下の Step 3 は帰納法の筋道だけ)
- 本問の問題文・制約・入力例は自作
概念図
ヒント(クリックで段階的に開示)
ヒント1(方向性)
$a\ge b$、$a=qb+r$ とする。$(a,b)$ から行けるのは $((q-k)b+r,\ b)$($L\le k\le\min(K,q)$)。$h_j=g(r+jb,b)$、$h_0=g(b,r)=:x$ と置くと、$1\le j<L$ の $h_j$ は手が無いので 0、$j\ge L$ では窓 $[\max(0,j-K),\ j-L]$ の mex。$x$ が 0 かどうかで形が変わる。
ヒント2(アプローチ)
$P=L+K$、$M=\lfloor (P-1)/L\rfloor$(値の最大)とする。$x=0$ なら引き算ゲームそのもので $h_j=\min(\lfloor (j\bmod P)/L\rfloor,\ M)$。小さい $L,K$ で $x\ge1$ の鎖を手で書いてみる。$L=3,K=7,x=1$ なら 1 | 000 222 3 11 | 1 000 222 3 11 | ...。
ヒント3(誘導)
- $x\ge1$ のとき 1 周期(長さ $P$)は「$x$ 1 個 → 値 $0..M$ の区画を $x$ だけ除いて順に → $x$ を $s_x-1$ 個」。区画の長さは $s_v=L$($v<M$)、$s_M=P-ML$
- 勝ち手の数: 行き先は鎖の添字の区間 $[\max(0,q-K),\ q-L]$。1 周期の中で値 $T$ を取る位置は高々 2 区間なので、「$[0,m)$ に値 $T$ がいくつあるか」を周期の倍数+端数で $O(1)$ に出し、差を取る
模範解答 (Python)
模範解答を表示する(まず自力で解いてから)
import sys
def main():
data = sys.stdin.buffer.read().split()
n, L, K = int(data[0]), int(data[1]), int(data[2])
P = L + K # 鎖の周期
M = (P - 1) // L # 値の最大
last = P - M * L # 値 M の区画の長さ(1..L)
ML = M * L
def size(v): # 基本列で値 v が占める長さ
return L if v < M else last
def h(t, x): # 鎖の t 番目(0 <= t < P)、先頭の値が x
if x == 0:
return min(t // L, M)
if t == 0:
return x
p = t - 1
if p < x * L:
return p // L
sx = size(x)
if p < P - sx:
return min((p + sx) // L, M)
return x
def spans(T, x): # 1 周期のうち値 T を取る区間 [l, r) のリスト
if T > M:
return ()
if x == 0:
return ((T * L, T * L + size(T)),)
sx = size(x)
if T == x:
return ((0, 1), (P - sx + 1, P))
if T < x:
return ((T * L + 1, T * L + L + 1),)
return ((T * L - sx + 1, T * L + size(T) - sx + 1),)
def prefix(T, x, m): # 0 <= j < m で h_j == T の個数
sp = spans(T, x)
whole, rest = divmod(m, P)
c = 0
for l, r in sp:
c += whole * (r - l)
if rest > l:
c += min(rest, r) - l
return c
gs = []
info = []
for i in range(n):
a = int(data[3 + 2 * i])
b = int(data[4 + 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 k in range(len(qs) - 1, 0, -1): # h を手で展開(呼び出しを省く)
t = qs[k] % P
if x == 0:
x = t // L if t < ML else M
elif t:
p = t - 1
if p < x * L:
x = p // L
else:
sx = L if x < M else last
if p < P - sx:
p += sx
x = p // L if p < ML else M
q = qs[0]
gs.append(h(q % P, x))
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):
if q < L:
continue # この組では手が無い
T = G ^ g
lo = q - K if q > K else 0 # 行き先の鎖の添字 [lo, q-L]
cnt += prefix(T, x, q - L + 1) - prefix(T, x, lo)
print("First")
print(cnt)
main()
計算量: 1 組あたり互除法の段数 $O(\log\max(a,b))$、勝ち手の数え上げは 1 組 $O(1)$。$N=2\times10^5$ で $L,K$ とも乱数 0.71 s、$L=2,K=7$ で 0.84 s、全組が隣り合うフィボナッチ数(商がすべて 1 の最悪ケース)で $L=K=1$ 1.72 s・$L=2,K=3$ 1.61 s、いずれも約 70 MB(Python 3.14.8、Apple M5 Pro、負荷平均約 22 での実測、起動込み)。
Step-by-Step 解説
1鎖と窓
$(qb+r,b)$ から $b$ の $k$ 倍を引くと鎖の添字が $q$ から $q-k$ に下がる。$L\le k\le\min(K,q)$ なので行き先は $[\max(0,q-K),\ q-L]$。$q<L$ なら手が無い(値 0)。$j=0$ の位置だけは大小が入れ替わった別の組 $(b,r)$ で、その値 $x$ は互除法を 1 段深く進めて求める(後ろから畳む)。
2$x=0$ なら引き算ゲームそのもの
$h_0=0$ は「0 個の山」と同じなので、鎖は「$L$〜$K$ 個取る」引き算ゲームの値の列に一致する。$P=L+K$ の周期で、値 $v$ が $L$ 個ずつ並び、最後の値 $M$ だけ $P-ML$ 個。
$$h_j=\min\!\left(\left\lfloor\frac{j\bmod P}{L}\right\rfloor,\ M\right)\qquad(x=0)$$
3$x\ge1$ だと区画が 1 か所ずれる
$L=3,K=7$($P=10,M=3$)の実測:
| $x$ | 1 周期 |
|---|---|
| 0 | 000 111 222 3 |
| 1 | 1 000 222 3 11 |
| 2 | 2 000 111 3 22 |
| 3 | 3 000 111 222($s_3=1$ なので末尾は 0 個) |
$h_1..h_{L-1}$ は手が無いので 0、$h_L$ も窓が $\{h_0\}=\{x\}$ だけなので 0。そのあとは「値 $v$ の区画が窓から外れると $v$ がまた出せる」引き算ゲームの仕組みで区画が順に並ぶが、値 $x$ だけは先頭に 1 個先に置かれているため、$x$ の区画は「先頭の 1 個」と「周期の末尾の $s_x-1$ 個」に分かれる。窓の長さ $K-L+1$ と区画の長さ $L$ の関係から各位置の mex がこの列と一致することを帰納法で確かめる筋道だが、一般の証明は書いていない。代わりに $K\le40$ の全 $(L,x)$(鎖 4323 本・各 6 周期、964368 か所)で漸化式と一致することを確かめた。
4値を $O(1)$ で
$t=q\bmod P$、$p=t-1$ として、$t=0$ なら $x$、$p<xL$ なら $\lfloor p/L\rfloor$、$p<P-s_x$ なら $\min(\lfloor (p+s_x)/L\rfloor,M)$、それ以外は $x$。$x$ は前の段の値で、最初は $(d,0)$ の 0。
5勝ち手の数
$G\ne0$ なら、組 $i$ を値 $t=G\oplus g_i$ に変える手を数える。値 $T$ の位置は 1 周期の中で、$T<x$ なら $[TL+1,\ TL+L+1)$、$T>x$ なら $[TL-s_x+1,\ TL+s_T-s_x+1)$、$T=x$ なら $[0,1)$ と $[P-s_x+1,P)$。添字の区間 $[lo,hi]$ の中の個数は「$[0,m)$ の個数」の差で、周期の倍数部分と端数部分に分けて足す。窓の長さ $K-L+1<P$ なので、同じ値が窓に 2 回以上現れることもある($T=x$ の 2 区間や、長さ $L$ の区画が窓にまるごと入る場合)。Day178-Q1 の「$t\le K$ なら 1 手」はもう成り立たない。
迷った他案と採らなかった理由
| 案 | 計算量 | 採否 | 理由 |
|---|---|---|---|
| Grundy 数の表(メモ化) | $O(A^2(K-L))$ | 検算用のみ | $10^{18}$ では不可能 |
| 下限を無視して Day178-Q1 の式(周期 $K+1$)を使う | $O(\log)$ | 不採用(誤り) | 3000 個の和で 888 個の勝敗を誤る(実測) |
| 引き算ゲームの値 $\lfloor (q\bmod P)/L\rfloor$ をそのまま使い、$x$ を無視 | $O(\log)$ | 不採用(誤り) | 627/3000 誤り(実測) |
| $x\ge1$ の式を $x=0$ にも使う(「$x$ を先頭に置き、$s_x-1$ 個を末尾へ」) | $O(\log)$ | 不採用(誤り) | 826/3000 誤り(実測)。$x=0$ では先頭の 0 と $h_1..h_{L-1}$ の 0 がつながって区画が割れない |
| 勝ち手を窓の中で 1 つずつ数える | $O(K-L)$/組 | 不採用 | $K-L$ が $10^{18}$ まであるので不可能 |
| 周期列の区間で数える(本解) | $O(N\log V)$ | 採用 | 0.71〜1.72 s |
前提が変わったら
- $k$ の候補が区間でない(例: $k\in\{1,3,4\}$)なら、1 つの山の引き算ゲームでも周期は一般に長く、前周期もある。鎖ごとに周期検出(Q2 と同じ発想)が要り、本問の閉じた式は使えない
- misère(最後に指した人の負け)なら XOR が使えない。未調査
- 勝ち手を 1 つ出力なら、
spansの区間から窓に入る添字を 1 つ選んで $k=q-j$ を返すだけで、同じ計算量で済む
よくあるミス
| ミス | 原因 | 正しい書き方 |
|---|---|---|
| $q<L$ の組でも手があると思う | 「小さい方の倍数を引く」を $k\ge1$ と読む | $q<L$ なら値 0・勝ち手 0。入力例 1 の $(5,5)$ |
| $x=0$ を $x\ge1$ と同じに扱う | 区画のずれを一般化しすぎる | $x=0$ は引き算ゲームそのもの |
| 周期を $K+1$ や $K-L+1$ にする | 上限だけの版や窓の長さと混同 | 周期は $L+K$ |
| 勝ち手を「窓に $T$ があれば 1」とする | Day178-Q1 の「並べ替え」の性質を持ち込む | 同じ値が窓に複数あるので個数を数える |
| 末尾区画 $M$ の長さを $L$ とする | $P$ が $L$ で割り切れるとは限らない | $s_M=P-ML$(1〜$L$) |
次のステップ
- 発展1: Step 3 の帰納法を最後まで書き、$x\ge1$ の列が漸化式を満たすことを証明する(窓が値 $x$ の 2 区画をまたぐ場合が要)
- 発展2: 「勝ち手を 1 つ出力」に変える(
spansと窓の交わりから添字を逆算) - 発展3: $k$ の候補が一般の有限集合のときの鎖を、Q2 の周期性の証明書の考え方で扱う
検証ログ(本セッションで実行した数値)
- 鎖の式(実測): $1\le L\le K\le40$、$0\le x\le M$ の全 4323 本の鎖を各 $6P$ 項まで mex の漸化式で作り、式と 964368 か所すべて一致
- 1 組の Grundy 数(実測): $1\le L\le K\le8$、$1\le a,b<120$ の全 509796 組で、全局面のメモ化 mex と一致。値の最大は $M$ を超えなかった
- 和と勝ち手の数(実測): $1\le L\le K\le7$、1〜4 組・各値 120 以下の乱数入力で、最終版 1500 個(先手勝ち 735)・展開前の版 3000 個(先手勝ち 1454)が全手列挙の全探索と勝敗・勝ち手の数とも全件一致
- 誤った方法(実測、同じ 3000 個で勝敗の不一致): 下限を無視 888、$x$ を無視 627、$x=0$ の特別扱いを忘れる 826
- 時間(実測、起動込み、$N=2\times10^5$、Python 3.14.8、負荷平均約 22): 乱数 0.71 s、$L=2,K=7$ 0.84 s、フィボナッチ最悪 1.61〜1.72 s、最大常駐 約 70 MB。Python 3.9.6・展開前の版では同じ入力が 1.37〜3.17 s だった
- 扱っていない範囲: 一般の証明、文献の確認、misère 版、$k$ が区間でない版