Day 087-Q5 — べき乗和の高速計算(連続点 Lagrange 補間 / Faulhaber の公式)

2026-07-10 赤色 Master / Phase 8+ ★★★★★★★★★ 多項式補間・Faulhaberの公式

問題

正整数 $N,K$ が与えられる。$S=\sum_{i=1}^{N} i^K \pmod{10^9+7}$ を求めよ。

制約

パラメータ範囲備考
$N$$1 \le N \le 10^{18}$直接計算は不可能
$K$$0 \le K \le 2\times10^5$多項式の次数を決める

入出力例

入力例1

3 2

出力例1

14

入力例2

10 1

出力例2

55

例1: $1^2+2^2+3^2=14$(直接計算範囲)。例2: $1+\dots+10=55$(補間を要する範囲、Step 4で手計算検証)。

概念図: $K+2$ 点から多項式 $S(x)$ を復元して $x=N$ を評価

S(x) は次数 K+1 の多項式 → K+2 個の点 x=0..m で一意に決まる x=0 x=1 x=2 x=m x=N(外挿) prefix/suffix 積 + 階乗前計算 → O(K) で N での値を評価

ヒント

ヒント1(方向性)

$N$ は最大 $10^{18}$ で素直な計算は不可能。$K \le 2\times10^5$ は小さい。$S(x)=\sum_{i=1}^x i^K$ を $x$ の関数として見る。

ヒント2(アプローチ)

$S(x)$ は次数 $K+1$ の多項式(Faulhaber の公式)。$x=0,\dots,K+1$ の $K+2$ 点の値を愚直計算し、連続整数点での Lagrange 補間で $x=N$ を $O(K)$ で評価する。

ヒント3(ほぼ答え)
# y[i] = S(i), i=0..m (m=K+1)
# prefix[i] = Π_{j<i}(N-j), suffix[i] = Π_{j>=i}(N-j)
# term_i = y[i] * prefix[i]*suffix[i+1] * inv(i!) * inv((m-i)!) * (-1)^(m-i)
# answer = Σ term_i

模範解答

import sys

MOD = 10**9 + 7

def solve():
    data = sys.stdin.buffer.read().split()
    N = int(data[0]); K = int(data[1])
    m = K + 1
    size = m + 1

    y = [0] * size
    for i in range(1, size):
        y[i] = (y[i - 1] + pow(i, K, MOD)) % MOD

    if N < size:
        print(y[N])
        return

    prefix = [1] * (size + 1)
    suffix = [1] * (size + 1)
    for i in range(size):
        prefix[i + 1] = prefix[i] * ((N - i) % MOD) % MOD
    for i in range(size - 1, -1, -1):
        suffix[i] = suffix[i + 1] * ((N - i) % MOD) % MOD

    fact = [1] * size
    for i in range(1, size):
        fact[i] = fact[i - 1] * i % MOD
    inv_fact = [1] * size
    inv_fact[size - 1] = pow(fact[size - 1], MOD - 2, MOD)
    for i in range(size - 1, 0, -1):
        inv_fact[i - 1] = inv_fact[i] * i % MOD

    ans = 0
    for i in range(size):
        num = prefix[i] * suffix[i + 1] % MOD
        denom = inv_fact[i] * inv_fact[size - 1 - i] % MOD
        term = y[i] * num % MOD * denom % MOD
        if (size - 1 - i) % 2 == 1:
            term = (-term) % MOD
        ans = (ans + term) % MOD

    print(ans % MOD)

solve()

計算量: 点の計算 $O(K\log K)$、補間 $O(K)$。全体 $O(K\log K)$、$N$ の大きさに依存しない。

Step-by-Step 解説

Step 1: $S(x)$ が多項式である理由

Faulhaber の公式より $\sum_{i=1}^x i^K$ は $x$ について次数 $K+1$ の多項式で表せる。

Step 2: サンプル点の計算

$x=0,\dots,m$($m=K+1$)の値を累積和で計算(各点 $O(\log K)$、全体 $O(K\log K)$)。

Step 3: 連続点 Lagrange 補間

ノードが等間隔の整数のため分母 $\prod_{j\ne i}(i-j)=i!\,(m-i)!\,(-1)^{m-i}$ に閉じた式があり、分子は前から積んだ prefix と後ろから積んだ suffix の積で $O(1)$。全体 $O(K)$ で $x=N$ を評価できる。

Step 4: 手計算による検証($N=10,K=1$)

$i$numdenom符号寄与
0722+$0\times36=0$
1801$-80$
2902+$135$

合計 $0-80+135=55=S(10)$ と一致。

よくあるミス

ミス原因正しい書き方
$N \le m$ でも補間しようとするsuffix[i+1] が $N-j=0$ を含み特別扱いが必要$N<size$ なら直接 y[N] を返す分岐を先に置く
符号 $(-1)^{m-i}$ を付け忘れる連続点補間特有の符号処理を誤解(size-1-i)%2==1 のとき負にする
$K=0$(点が2つ)を特別扱いしようとする境界ケースで配列サイズを誤りがち$size=K+2$ を一般式のまま使えば自動的に正しい

次のステップ

  • 発展問題: 複数の $K$ に対するクエリ($K$ ごとに $O(K\log K)$ 前処理)
  • 発展問題: 等間隔でない点集合での高速多点補間(Subproduct Tree・$O(K\log^2K)$)

自己評価

理解度: / /

自分の回答:

気づき・メモ: