$$ \def\bra#1{\mathinner{\left\langle{#1}\right|}} \def\ket#1{\mathinner{\left|{#1}\right\rangle}} \def\braket#1#2{\mathinner{\left\langle{#1}\middle|#2\right\rangle}} $$

◇◇tech003:関数DP◇◇


☆概要

DPテーブルを $$DP[i][j]=i{\rm 番目の要素まで見たときの座標}j{\rm での値}$$ という形で保持するDPについて、$0\leq j\leq 10^9$のような広範囲の座標を保持したくなったとき、通常の方法ではメモリも実行時間も足りなくなってしまうが、各座標での値の代わりに関数そのものの性質を表すパラメータを保存することでこれらの制約を突破できることがある。

☆本文

$$DP[i][j]=i{\rm 番目の要素まで見たときの座標}j{\rm での値}$$ という形のDPは $$DP[i](x)=i{\rm 番目の要素まで見たときの座標}x{\rm での値}$$ という「関数を保持するDP」と考えることが有効である場合がある。その条件は、$DP[i](x)$が単純な形の関数で表せる場合である。

その代表的な例が、$DP[i]$が折れ線グラフで表せる場合である。ARC070Eは、$i$番目の机を動かした結果、その左端の座標が$x$になる場合の最小コストは画像の図1,3,5のような折れ線グラフで表せるという問題であった。$i$番目の机についての最小コストのグラフは$i-1$番目の机についてのグラフから求めることができ、折れ線の傾きが変化する座標と傾きがゼロの点での$y$座標を保持するDPが想定解だった(通常のDPによる解法は部分点解法となっていた)。データの保持の仕方は通常のDPテーブルに限らず、保持すべきパラメータの数が変化する場合にはmultisetやpriority_queueを使うことも視野に入れなければならない。

☆追記

ARC077Eは、一次関数を足し合わせる関数DPの問題だった。なので、多項式を足し合わせる方法をメモしておくことにした。例として二次関数を扱う。二次関数 $$a_1x^2+b_1x+c_1$$ と $$a_2x^2+b_2x+c_2$$ を足し合わせると $$(a_1+a_2)x^2+(b_1+b_2)x+(c_1+c_2)$$ となる。これを利用して、それぞれの座標について二次の係数を格納する配列と一次の係数を格納する配列と零次の係数(定数)を格納する配列を作っておけば、最後にそれぞれ$x^i$をかけることで値を求めることができる。係数を足し合わせるときに配列のすべての要素を参照していては意味がないので、imos法の要領で範囲に足す方法を使う。すべての座標が同じ関数に従うのであればこのような方法は必要ないが、ARC077Eのように座標によって異なる関数を足し合わせたい場合には有効である。

☆問題

戻る