昨日の 第4回ドワンゴからの挑戦状 予選 C 問題 で、分割数 DP を必要とする問題が出されました。
蟻本をよく読んでいる人ならご存知のとおり、この DP は dp[i][j] := j を i 分割する時の場合の数
とするとき、 dp[i][j] = dp[i][j-i] + dp[i-1][j]
となります。しかし、蟻本の解説だけだとどうもわかりにくいです (少なくとも自分は理解するまでに N 時間かかりました)。
というわけで、ドワコンのあいだに実際に私が考察した、蟻本とは違うアプローチ (本質的には同じ) でこの式を導出してみます。
若干遅い解法
まず、なにを解きたいのかをちゃんと式で書きましょう。ちゃんと書くと、以下のようになります。
の
分割
→
を満たす数列
の総数
まず、 番目の要素
の値を
にすることを考えましょう。
は他のどの値よりも小さいか等しいため、
は必ず
以上の値を取ります。
番目の値を確定させると、残った
個の要素に対して同様に分割数 DP を適用すれば良いことが分かります。このとき、各要素は必ず
以上の値をとるのですから、全ての要素から
引いて考えても問題ありません。
以上のことから、以下のような DP が立てられます。
見た目でわかるとおり、これを実装すると 3 重ループになります。 という近似より、計算量はたぶん
です (間違っていたら教えてください)。実際に ドワコンの問題でこの漸化式を使っても通る のですが、次に説明する工夫をすることで log を取ることができます。
速い解法へ
基本的には、先ほどの式を応用させるイメージでやります。式を再掲します。
という部分に着目します。
を定数としてみたとき、
から
の倍数を引いていることが分かります。ここで、おもむろに
の部分だけシグマから抜き出します。
ここで、 とおくと、
\begin{align} dp\left[ i \right] \left[ j \right] &= \sum_{x'=0}^{\lfloor \frac{j'}{i} \rfloor} dp\left[ i-1 \right] \left[ j'- i*x' \right] + dp\left[ i-1 \right] \left[ j \right] \\ &= dp\left[ i \right] \left[ j' \right] + dp\left[ i-1 \right] \left[ j \right] \\ &= dp\left[ i \right] \left[ j-i \right] + dp\left[ i-1 \right] \left[ j \right] \end{align}
このように変形できて、無事 になりました。終わり! (雑)
ということで、蟻本とは少し違う導出をやりました。