Monotone Minima と SMAWK
以下のような問題があるとする。
- 例題1
- $N \times M$ の2次元配列 $A$ がある
- 各行毎に、その行の最小値を求めたい
A i\j 0 1 2 3 0 3 1 4 1 → 1 1 5 9 2 6 → 2 2 5 3 5 8 → 3 3 9 7 9 3 → 3
これは、通常なら、各行毎にチェックして $O(NM)$ かける他にない。
ところが、$A$ がある“都合の良い条件”を満たしていると、$O((N+M) \log{N})$ や $O(N+M)$ でできる。
Monotone性
「$i$ の増加に伴って、最小値を取るindex $j$ が単調増加」の時、$A$ は「Monotone」という。
Monotone i\j 0 1 2 3 4 0 9 [3] 4 8 5 $i$ の増加につれ、最小値をとる $j$ は右に 1 5 [1] 9 2 6 2 5 7 6 [4] 8 3 8 7 9 3 [2] 4 7 9 8 8 [6]
また、$A$ から行と列を抜き出した任意の部分行列 $A'$ がMonotoneであれば、$A$ は「Totally Monotone」という。
Totally Monotone i\j 0 1 2 3 4 0 [7] 11 20 24 50 1 23 [13] 17 16 36 2 47 22 21 [16] 31 3 75 42 37 [25] 34 ↓たとえば、i=[0,2,3], j=[1,2,4] を抜き出してみても... i\j 1 2 4 部分行列でも 0 [11] 20 50 Monotone性が保たれている 2 22 [21] 31 3 42 37 [34]
元の例題1に立ち返ると、$A$ が、
- Monotone であれば、Monotone Minima により、$O(N+M \log{N})$
- Totally Monotone であれば、SMAWK により、$O(N+M)$
で各行の最小値を求める方法がある。
Monotone判定
実際に競技プログラミングの問題として Monotone 性を利用するのが出てくる場合、 $A$ は何かしら規則的な方法で生成されるのが大半だろう。
その場合「Monge性」を持つことを使うことが多い(らしい)。
「Monge性を満たすならTotally Monotone性も満たす」という性質がある。
Monotone Minima
$i$ について半分ずつ範囲を狭めていく。
i\j 0 1 2 3 4 5 6 7 8 9 N=7 M=10 として 0 x x x x 1 x x x x まず、Nの真ん中の i=3 について O(M) かけて最小値を探す 2 x x x x 3 # # # # #[#]# # # # j=5 のときに最小値を取るとすると、 4 x x x x x Monotone性より、左下と右上は可能性を除外できる。 5 x x x x x 6 x x x x x 結果、左上と右上の2つの矩形が残る。 ※ #:値を調べた箇所 [#]:調べた中での最小値 x:最小値の可能性がなくなった箇所 i\j 0 1 2 3 4 5 6 7 8 9 分割された2つの矩形で再帰的に同じことをする。 0 x x x x - - - - 行 [0,1,2] の真ん中 i=1 と、 1 #[#]# # # # - - - - 行 [4,5,6] の真ん中 i=5 について探索する 2 x - - - - この探索幅は、1箇所のみ重複するが、あわせておよそ O(M) である。 3 - - - - - - - - - - 4 - - - - - x x 最小値を見つけたら、 5 - - - - - # #[#]# # 同様に、それぞれの左下と右上は可能性を除外でき、4つの矩形が残る。 6 - - - - - x x ※ -:前回までで調べた or 可能性がなくなり、調べる必要が無くなった箇所 i\j 0 1 2 3 4 5 6 7 8 9 再帰的に同じことをする。 0 [#]# - - - - - - - - 探索幅は、あわせて O(M) である。 1 - - - - - - - - - - 2 - # #[#]# # - - - - 3 - - - - - - - - - - log N 回繰り返すと、全ての i について最小値の位置が判明する。 4 - - - - -[#]# # - - 5 - - - - - - - - - - 6 - - - - - - - # #[#]
探索幅は $O(M)$ と言っているが、厳密には重複が発生している。その回数は、全体を通して $O(N)$ となる。よって、全体で $O(N+M \log{N})$ で求められる。
SMAWK
- わかりやすい具体例が載っている論文(英語, pdf)
定数倍の関係で、必ずしも Monotone Minima より早いとは限らない?
Monotone Minima の方がわかりやすく、実装も容易で、計算量の差もlog1つだけなので、 競技プログラミングでは無理してこちらを使う必要性は薄いかも?
アルゴリズムの日本語の文章化は以下のブログが詳しい。
応用例
最小値畳み込み
Monotone Minima や SMAWK を使うと、$C_i=\min_j(A_j+B_{i-j})$ みたいな $C$ も、$A,B$ の性質次第で高速に求められる。
$B$ が下に凸な時
$B$ が下に凸な時、それを以下のように並べた行列はMongeである。
B = { 9, 4, 1, 0, 1, 4 } ↓ i\j 0 1 2 3 4 5 6 ... 0 9 ∞ ∞ ∞ ∞ ∞ ∞ これはMonge 1 4 9 ∞ ∞ ∞ ∞ ∞ 2 1 4 9 ∞ ∞ ∞ ∞ 3 0 1 4 9 ∞ ∞ ∞ 4 1 0 1 4 9 ∞ ∞ 5 4 1 0 1 4 9 ∞ 6 ∞ 4 1 0 1 4 9 7 ∞ ∞ 4 1 0 1 4 :
で、Mongeな行列に対し、列全体に同じ値を加算してもMonge性は保たれるという性質がある。
A = { 3, 1, 4, 1, 5, 9, 2 } i\j 0 1 2 3 4 5 6 +3 +1 +4 +1 +5 +9 +2 0 12 ∞ ∞ ∞ ∞ ∞ ∞ これもMonge 1 7 10 ∞ ∞ ∞ ∞ ∞ 2 4 5 13 ∞ ∞ ∞ ∞ 3 3 2 8 10 ∞ ∞ ∞ 4 4 1 5 5 14 ∞ ∞ 5 7 2 4 2 9 18 ∞ 6 ∞ 5 5 1 5 13 11 7 ∞ ∞ 8 2 4 10 6
これは、$X_{i,j}=A_j+B_{i-j}$ の行列になっている。これで行毎に最小値を取ったものは、まさしく $C$ である。
$B$ のみが下に凸な場合、畳み込みの添字に注意。$X_{i,j}=A_{i-j}+B_j$ としてしまうと上手くいかない。
LARSCH
SMAWKは、あらかじめ全ての $A$ が(関数で部分的に求めるにしろ)わかっていないといけない。
しかし動的計画法で順番に求める必要がある場合に、それだと上手くいかないことがある。
LARSCHは、「$\arg\min_k A_{j,k}$ の値が求まって、はじめて $A_{i,j+1}$ の値を使用できる」場合でも求めることができる。