ツバサの備忘録

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

AOJ 2611 - 順位付け

問題
提出コード

解法

木の2乗DPとかなんとか言われてるやつです。
問題文をじっくり読むと、入力が木になっていて、そのなかで順位付けをしていくことがわかります。木全体の根は、入力時点で一番高さが高かった頂点です。
木の高さがすべて異なる場合は簡単に求めることができますが、同じ高さの場合があるのでさっと解くことはできません。
以下のようなDPを考えます。

  • dp[v][i] = vを根とする部分木について、高さの種類数がiとなるようにしたときの、高さの決め方

頂点が葉だった場合は、dp[v][1] = 1となります。
それ以外の場合、子についてそれぞれ探索してから、自分自身にマージしていくことを考えます。
tmp[i] = 子についていくつか見た後の、現時点での値(高さがi種類となるようなパターン数)
ここに、dp[c][j]達をマージしていきます。cは、今見ている子です。
tmp[i]dp[c][j]を組み合わせると、
新たな種類数は[max(i,j) , i + j]区間のいずれかの値になります。
新たな種類数がkになるパターンを考えます。
i,j種類を組み合わせてk種類にする際、

  • k種類の中から、i個を選び、tmp側の高さを全て割り振る

という操作をまず行うと、k種類の中から、すでに選択されたi個と、まだ選択されていないk-i個にわかれます。
ここから、j個の頂点に高さを割り当てなければなりませんが、この中で、k-i個は残りのj個のいずれかが選ばないといけないので無視します。
ということで、残ったi個の中から、j - (k - i)個を選び、jに割り当てる必要があります。
割り振る場所を決めてしまうと、順番は一意に決まるので、最終的に、i,j種類を組み合わせてk種類を作成する際のパターン数は、
_{k}C_{i} \times _{i}C_{(i + j - k)}通りです。
ということで、ここにtmp[i] \times dp[c][j]をかけたものを、新たに足しこめばよいです。
f:id:emtubasa:20200501143824j:plain
このようにして、tmpdp[c]を組み合わせて新たなtmpを作成、という操作を繰り返します。
その後、最終的なtmpについて、dp[v][i] = tmp[i - 1]とすればよいです。今見ている頂点v自身を種類数に加えるためです。
計算量についてですが、一見O(N^{4})かかるように見えますが、一番内側のループ以外が合わせてO(N^{2})になるみたいです。
詳しい解析はこちらを参照してください。

snuke.hatenablog.com