Day 024-Q2 — 確率的最適停止 (最良選択問題・秘書問題の拡張)

2026-05-07 赤色 Master / Phase 8+ ★★★★★★★★★ 期待値 DP / 最適停止

問題

$N$ 人の応募者をランダム順に面接。各面接後に「採用」or「次へ進む」を即座に決定。一度パスした応募者は採用不可。面接ごとにコスト $C$ が発生し、スコア $k$ の人を採用すれば報酬 $k$。最後まで誰も採用しない場合は報酬 $0$。最適戦略の期待利益を有理数で求めよ。

制約

$1 \le N \le 5000$
$1 \le C \le 100$

入出力例

入力例 1

3 1

出力例 1

11/6

ヒント (段階的開示)

ヒント1: 方向性
DP を後ろから。$dp[i][j]$ = 「$i$ 番目以降を面接、これまでの最高スコアが $j$」のときの最適期待利益。
ヒント2: アプローチ
残り人数の条件付きでスコア分布を計算。順列の対称性から「残り N-i+1 個のスコア」は等確率に分布。
ヒント3: 誘導
$dp[i][j] = -C + E_s[\max(s, dp[i+1][\max(j,s)])]$。Fraction で誤差なし計算。

模範解答 (Python)

from fractions import Fraction
import sys
input = sys.stdin.readline

def solve():
    N, C = map(int, input().split())
    C_frac = Fraction(C)

    # 後ろから DP(簡易版)
    dp = [Fraction(0)] * (N + 1)
    for i in range(N, 0, -1):
        dp_new = [Fraction(0)] * (N + 1)
        denom = Fraction(1, N - i + 1)
        for j in range(i - 1, N + 1):
            val = Fraction(0)
            cnt_low = j - (i - 1)
            if cnt_low > 0 and j > 0:
                floor_val = dp[j]
                s_sum = Fraction(0)
                for s in range(1, j + 1):
                    s_sum += max(Fraction(s), floor_val)
                val += denom * Fraction(cnt_low, j) * s_sum
            for s in range(j + 1, N + 1):
                val += denom * max(Fraction(s), dp[s])
            dp_new[j] = -C_frac + val
        dp = dp_new

    print(dp[0])

solve()

Step-by-Step 解説

1定式化
秘書問題のコスト・スコア拡張。最適停止理論の典型。
2状態設計
$dp[i][j]$ = 残り面接時の期待利益。後ろから DP。
3遷移
各 $s$ について「採用 ($s$)」 vs 「パス ($dp[i+1][\max(j,s)]$)」を $\max$ で選ぶ。
4分数演算
Fraction で誤差なしの期待値計算。

よくあるミス

ミス原因正しい書き方
コストを後で引くコストは面接ごと各ステップで -C
最後の人を強制採用パスも選択肢dp[N+1][j] = 0
浮動小数点誤差float 利用Fraction を使う

次のステップ

  • 複数採用枠の秘書問題
  • 最適停止と American option pricing

自己評価

自分の回答

気づき・メモ