Day 039-Q4 — Monge 行列 + 分割統治最適化 DP

2026-05-22 赤色 Master / Phase 8+ ★★★★★★★★★ Concave SMAWK / Divide & Conquer DP

問題

$N$ 個の都市(座標 $x_i$、ソート済み)を $K$ グループ(連続する集合)に分割して、各グループの最左端と最右端の距離の 2 乗のコスト和を最小化する。

$$\text{minimize} \quad \sum_{j=0}^{K-1} (x_{g_{j+1}-1} - x_{g_j})^2$$

制約

$2 \le K \le N \le 10^5$
$0 \le x_1 < x_2 < \cdots < x_N \le 10^9$
時間制限: 3sec / メモリ: 256MB
答えは 64bit 整数に収まる

入出力例

入力例 1

6 2
1 3 6 10 15 21

出力例 1

117

最適: [1,3,6,10] と [15,21] → $(10-1)^2 + (21-15)^2 = 81 + 36 = 117$。

概念図: 分割統治最適化 DP

dp[k][i] の最適分割点 opt(i) の単調性 i=1 i=2 i=3 i=4 i=5 i=6 opt: 0 0 1 2 3 4 opt(i) が単調増加 → 分割統治 O(N log N) が使える rec([1,6], [0,5]) rec([1,3], [0,opt]) rec([4,6], [opt,5]) 各再帰レベルで合計 O(N) の仕事 × O(log N) 深さ → O(N log N) per layer K レイヤーで合計 O(KN log N)

ヒント(段階的開示)

ヒント1: DP の定式化
$dp[k][i]$ = 都市 $1..i$ を $k$ グループに分割した最小コスト。
$dp[k][i] = \min_{k-1 \le j < i}(dp[k-1][j] + C(j+1, i))$
$C(l, r) = (x_r - x_l)^2$(グループ $[l..r]$ のコスト)
ヒント2: 最適分割点の単調性
コスト $C(j+1, i) = (x_i - x_{j+1})^2$ は $j$ について「四辺形不等式」を満たす(凸型コスト)。これにより最適分割点 $opt(i)$ は $i$ について単調増加する。
ヒント3: 分割統治の実装
def rec(il, ir, jl, jr):
    if il > ir: return
    im = (il + ir) // 2
    best_val, best_j = INF, jl
    for j in range(jl, min(jr, im - 1) + 1):
        v = dp_prev[j] + cost(j + 1, im)
        if v < best_val:
            best_val, best_j = v, j
    dp_cur[im] = best_val
    rec(il, im - 1, jl, best_j)    # 左半分: opt <= best_j
    rec(im + 1, ir, best_j, jr)    # 右半分: opt >= best_j

模範解答 (Python)

import sys
input = sys.stdin.readline

def solve():
    N, K = map(int, input().split())
    X = list(map(int, input().split()))

    INF = float('inf')

    def cost(l, r):  # 1-indexed [l,r]
        return (X[r-1] - X[l-1]) ** 2

    # k=1 の初期化
    dp = [INF] * (N + 1)
    dp[0] = 0
    for i in range(1, N + 1):
        dp[i] = cost(1, i)

    for k in range(2, K + 1):
        ndp = [INF] * (N + 1)

        def rec(il, ir, jl, jr):
            if il > ir:
                return
            im = (il + ir) // 2
            best_val = INF
            best_j = jl
            for j in range(jl, min(jr, im - 1) + 1):
                if dp[j] == INF:
                    continue
                v = dp[j] + cost(j + 1, im)
                if v < best_val:
                    best_val = v
                    best_j = j
            ndp[im] = best_val
            rec(il, im - 1, jl, best_j)
            rec(im + 1, ir, best_j, jr)

        rec(k, N, k - 1, N - 1)
        dp = ndp

    print(dp[N])

solve()

Step-by-Step 解説

1DP の定式化
$dp[k][i]$ = 都市 $1..i$ を $k$ グループに分割した最小コスト。遷移は最適分割点 $j$ を全探索。
2四辺形不等式の確認
$(x_c - x_a)^2 + (x_d - x_b)^2 \le (x_d - x_a)^2 + (x_c - x_b)^2$ の確認($a \le b \le c \le d$)。成立すれば最適分割点が単調。
3分割統治最適化
中点 $im$ に対して最適 $j$ を探し、左右の区間の探索範囲を縮小する。各層 $O(N)$、$O(\log N)$ 層で $O(N \log N)$。
4K 層の反復
$k = 2$ から $K$ まで反復。前の層の dp を使って次の層を計算。
5再帰の境界
il > ir で終了、min(jr, im-1) で $j < im$(自己分割回避)を保証。

計算量

各層: $O(N \log N)$(分割統治最適化)
全体: $O(KN \log N)$
WQS 二分探索と組み合わせると: $O(N \log N \log C)$

よくあるミス

ミス原因正しい書き方
単調性を確認せずに適用コストが四辺形不等式を満たさない小さな例で検証してから実装
終了条件 il > ir を忘れる無限再帰if il > ir: return を先頭に
k グループの最小都市数を無視j < k-1 での探索rec(k, N, k-1, N-1) で初期化
j < im の制約漏れ自己分割が発生min(jr, im-1) で j < im を保証

次のステップ

  • 発展: $K$ が大きい場合 → WQS 二分探索 (Aliens Trick) と組み合わせて $O(N \log N \log C)$
  • 応用: SMAWK アルゴリズムで $O(N)$ の最適化

自己評価

自分の回答

気づき・メモ