ツバサの備忘録

主に備忘録代わりに精進記録を載せていくつもりです。

Educational DP Contest / DP まとめコンテスト N - Slimes

問題
提出コード

解法

\displaystyle s_{i} = \sum_{j=1}^{i}a_{j}
とします。
N体のスライムを合体していくのではなく、1体の大きさs_{N}のスライムを、N体に分解していく、というようにして考えていきます。
このとき、大きさXのスライムを分解するときのコストはXになります。
dp[i][j] = 区間[i,j]のスライムが1体になっているとき、それらをすべて1体ずつにバラすために必要な最小コスト
とすると、答えはdp[1][N]になります。また、初期条件はdp[i][i]=0です。1体になった時点で、これ以上分ける必要が無いからです。
さて、1体のスライムをどのようにわけるとしても、必ずs_{j} - s_{i-1}のコストは必要になるので足す必要があります(ここで、s_{j} - s_{i-1}は、[i,j]区間a_{i}の総和をsを用いて表した式になります)。
あとは、どこでスライムを分断するか、です。
[i,k][k+1,j]とわけるとした場合、最終的な遷移は次のようになります。
dp[i][j] = min(s_{j}-s_{i-1}+dp[i][k]+dp[k+1][j])
ただし、i \leqq k \lt jです。
あとはこれをもとにして計算していけば答えを求めることができます。

感想

区間DPを、初めて再帰を使わずに書きました。が、再帰をした方がわかりやすいと個人的には思います。理由としては、引数に区間の端の情報をはっきりと書いているので、上のように式に表した時わかりやすいからです。今回自分の書いたコードは、区間の左端と、区間の幅をfor文の変数にしたため、ごちゃごちゃしています。今回のDPは、ここからさらに分断する変数(上でいうk)も必要になるので、書くのに時間がかかりました。
思考の推移としては以下の感じです。
制約をまず見たときに、O(N^{3})が間に合いそうなので、dpの添え字は3つか、2つで1つの要素を確定させるためにO(N)かけるかのどちらかだ、という目星を付けます。すると、操作の前後でスライムの順番が変わらないので、区間に対しての最善手を求めるとうまくいきそう、ということがわかり、区間DPを思いつきます。あとは、ある区間に対する最善手を考えたときに、まとめるのではなく分割していけば、わかりやすいDPがかけそう!となり、上の式を考えて、考察完了です。