Day 006-Q2 — 数論基礎

2026-04-19 水色 / Phase 4 ★★★★☆ 数論基礎(mod演算・nCr)

問題

$N$ 個のボールから $K$ 個を選ぶ組み合わせの数を $10^9 + 7$ で割った余りを求めてください。

入力形式

N K

制約

$0 \le K \le N \le 10^6$

入出力例

入力例 1

5 2

出力例 1

10

入力例 2

1000000 500000

出力例 2

149033233

ヒント (段階的開示)

ヒント1: 方向性
$C(N, K) = N! / (K! \times (N-K)!)$ ですが、大きな数の除算は mod では直接できません。
ヒント2: アプローチ
mod $p$ での除算は「逆元」を使います。フェルマーの小定理より、$p$ が素数のとき $a^{p-2} \equiv a^{-1} \pmod{p}$ が成り立ちます。
ヒント3: 誘導
MOD = 10**9 + 7
# 前計算: 階乗と逆元の階乗テーブル
fact = [1] * (N + 1)
for i in range(1, N + 1):
    fact[i] = fact[i-1] * i % MOD
inv_fact = [1] * (N + 1)
inv_fact[N] = pow(fact[N], MOD - 2, MOD)  # フェルマーの小定理
for i in range(N - 1, -1, -1):
    inv_fact[i] = inv_fact[i+1] * (i+1) % MOD

def comb(n, k):
    if k < 0 or k > n: return 0
    return fact[n] * inv_fact[k] % MOD * inv_fact[n-k] % MOD

模範解答 (Python)

import sys
input = sys.stdin.readline

def main():
    N, K = map(int, input().split())
    MOD = 10**9 + 7

    # 前計算: 0〜N の階乗テーブル
    fact = [1] * (N + 1)
    for i in range(1, N + 1):
        fact[i] = fact[i-1] * i % MOD

    # 逆元の階乗テーブル(フェルマーの小定理で計算)
    inv_fact = [1] * (N + 1)
    inv_fact[N] = pow(fact[N], MOD - 2, MOD)
    for i in range(N - 1, -1, -1):
        inv_fact[i] = inv_fact[i+1] * (i+1) % MOD

    def comb(n, k):
        if k < 0 or k > n:
            return 0
        return fact[n] * inv_fact[k] % MOD * inv_fact[n-k] % MOD

    print(comb(N, K))

main()

Step-by-Step 解説

1mod での除算の問題
$10^9$ 規模の $N$ では $N!$ が巨大になり、直接除算すると mod 演算を壊します。逆元を使って「除算」を「乗算」に変換します。
2フェルマーの小定理
素数 $p$ に対して $a^{p-1} \equiv 1 \pmod{p}$ が成り立つため、$a \times a^{p-2} \equiv 1 \pmod{p}$ → $a^{-1} \equiv a^{p-2} \pmod{p}$。
3逆元テーブルを O(N) で構築
個別に pow(fact[i], MOD-2, MOD) を呼ぶと $O(N \log p)$ になる。代わりに後ろから inv_fact[i] = inv_fact[i+1] * (i+1) % MOD で $O(N)$ に短縮。
4組み合わせの計算
$C(n, k) = n! \times (k!)^{-1} \times ((n-k)!)^{-1} \bmod p$

よくあるミス

ミス原因正しい書き方
N! % MOD を先に計算してから除算mod後は整数除算不可逆元を使う
pow(a, MOD-2, MOD) でなく普通のべき乗Python組み込みの pow(a, b, m) が高速pow(a, MOD-2, MOD)
k > n のケースを考慮しないC(n, k) = 0 になるif k < 0 or k > n: return 0

次のステップ

  • 発展問題: パスカルの三角形で $C(N, K)$ を $O(N^2)$ DP で求める($N$ が小さい場合)

自己評価

自分の回答

気づき・メモ