ミケ猫の小部屋

情報学、数学、語学および料理(暫定)について発信します

RE:ゼロから始めるLIS問題

最長部分増加列(LIS)問題は序列a_1 a_2 a_3 \dots a_nの単調増加の部分列の中で一番長い部分列の長さを求める問題である。最近ARC 104の問題

atcoder.jp

を見ていたらLIS問題を振り替えようと思います。

貪欲アルゴリズム

配列dp[i]があるとする。dp[i]は長さがiの部分増加列の最後の要素の最小値を表す。例えば列1 2 3 4 5全体に対して、長さが4になる部分増加列は1 2 3 4などの五通りある。その中で最後の要素の最小値は4なのでdp[4]=4になる。

このアルゴリズムは配列の要素ごとに以下のプロセスを繰り返す。

  1. 配列の要素a_iをみる
  2. 今の最長増加列の長さをmとすると、二分探索でa_iより大きい要素をdpから探す。
  3. 見つかったらその要素をa_iと置き換える。
  4. 見つからなかった場合は長さを1増やして、dp配列の最後をa_iと置く。

このアルゴリズムは簡単で、ツリー上のLIS問題にも適用する。

atcoder.jp

BITを用いたdpアルゴリズム

また配列dpを用意して、今回は dp_iを「iが最後となる部分増加列の長さ」にする。BITを使って効率よく dp_1から dp_kまでの最大値を探す。アルゴリズムは元の配列要素ごとに以下のプロセスを繰り返す。

  1. 配列の要素a_iをみる
  2.  dp_1 から dp_{a_i-1}までの最大値tmpを探す
  3.  dp_{a_i}tmp+1にする

この方法が成立する前提は全ての要素更新は要素を大きくすること。そして区間最大値は全部初めから計算したもの。この方法は貪欲アルゴリズムより複雑だけど、LISだけでなくより複雑な制約を扱える。例えばこのLaIS問題。

codeforces.com