Bookshelf(本棚) - joi2011-day4 解説
筆者: qnighy
本棚に本が一列に並んでいて、番号と重みが決められているとき、「ある本を取り除いて、任意の位置に再度挿入する」をその本の重み(の2倍)をコストとして実行できるとして、最小コストで本を番号通りの順番に戻す問題である。
解析
以下の事実に気づくことが重要である。
- どの本も、動かすとしても高々1回でよい。
- Sを本の部分集合とするとき、「S以外の本を動かすことで目的を達成できる」ことと「Sの番号が昇順になっている」ことが同値である。
後者を証明しよう。
(→) Sに属する本は動かしていないのだから、それらの間の順序は変化していないはずであるから、当然元から昇順であったはずである。■
(←) Sに属さない本を、1番の本から順番に移動するだけでよい。■
さらに、Sの重みの和と、移動に必要なコストは、線形の負の相関関係にあることが明らかであるから、条件を満たすSのなかで重み最大のものを考えればよい。
名前を付けるのであれば、「重み最大増加部分列」となるだろう。
w=1, O(N^2)解法
w=1のとき有名な最長増加部分列問題であるので、単純な動的計画法を用いることで20点を得られる。
w=1, O(NlogN)解法
同様に、最長増加部分列は二分探索を用いてO(NlogN)で書けることが知られている。これで30点が得られる。なお、wが1とは限らないときのO(N^2)の解法は省略する。
O(NlogN)解法
列を左側から順番に処理することを考える。各状態で
「今まで処理した列のなかで、i番の本を末尾にすえた部分列のうち重み最大のもの」
を記録していく。
すると、次の本がxだったとき、i<xなる本を末尾にすえた部分列のうち重み最大のものに本xを加えたものがその時点での最大として得られる。
つまりこれは、配列上の「特定の値の最大値更新」と「0からある範囲までの間の最大値取得」ができるデータ構造を必要としている。これを実現するために、RMQまたはmaxに対するFenwick Treeを使うことができる。
以上を実装することで満点が期待できる。