Educational DP Contest DP まとめコンテスト - noko206/AtCoder GitHub Wiki
これは何?
Educational DP Contest / DP まとめコンテスト の要点や感想をまとめたページです。
問題
R - Walk
★解説AC★
行列累乗。
$dp[n][i][j]:=$ 頂点 $i$ から 頂点 $j$ へ行く長さ $n$ のパスの個数
と定義したとき、状態遷移は以下のようになる。
$dp[n][i][j]=\sum_k dp[n-1][i][k]*a[k][j]$
天才をすると、これが行列の積で書けることがわかって、 $A^K$ の各成分の合計が答えとなることがわかる。
コツとしては、↓らしい……。
- 制約を見る
- $N \le 50$ や、 $K$ が $10^9, 10^{18}$ みたいな場合は、サイズ $N^2$ の行列を $K$ 乗したら解けるかも
- 繰り返しに着目
- 同じ状態遷移を繰り返すものは行列累乗かも
https://atcoder.jp/contests/dp/submissions/49358404
↑ 行列の掛け算と累乗の計算をするライブラリを作った(パクった)。
S - Digit Sum
桁DP。
$dp[i][j][smaller]:=$ $i$ 桁目まで決定したとき、 $D$ で割った余りが $j$ で、 $smaller$ が $1$ なら $K$ 未満、 $0$ なら $K$ と等しい値の個数。
と定義する。
桁DPの要は $smaller$ なので、そこの遷移に着目すると、
- 0 -> 0 :存在する
- 0 -> 1 :存在しない
- 1 -> 0 :存在する
- 1 -> 1 :存在する
となる。
それ以外のコツとしては、↓ のような感じ。
- 桁DPでは $K$ より大きい値となるような状態は考えない
- 大きな桁から考えることで $smaller$ を求めやすくする
- 初期化は $smaller$ が $1$ の状態に対して値を入れるといいかも?
- $1$ 以上 $K$ 以下の整数を考える時、 $0$ も含めて計算して、個数をあとから引くと実装が楽になりそう
https://atcoder.jp/contests/dp/submissions/49359262
T - Permutation
★解説AC★
挿入DP。
$dp[i][j]:=$ $i$ 番目までで、最後が $j$ のときの場合の数
- 都度 $1~i$ 番目が最後のときの場合の数を更新していく
- その過程で累積和が必要になるのでそれで高速化する
- 順列を考える問題は挿入DPであることを疑うのがよさそう
https://atcoder.jp/contests/dp/submissions/49562573
U - Grouping
★解説AC★ ※遷移式が思いつかなかった……。
部分集合の部分集合は $O(3^N)$ 。
$dp[S]:=$ 集合 $S$ をいくつかのグループに分けたときの総得点の最大値。
- 集合 $S$ の部分集合 $T$ を $1$ つのグループとして、部分集合 $S/T$ と合体する遷移を考える
- 集合 $T$ は集合 $S$ の部分集合なので、 $S/T$ は $S-T$ で計算可能
- 部分集合をループするときは
for (int T = S; ; T = (T - 1) & S)
と書く- 終了条件や continue 条件は適宜追加する
https://atcoder.jp/contests/dp/submissions/49563903
V - Subtree
全方位木DP。
ライブラリを持っていたのでペタリ。 あとは遷移式を頑張って立てる。
- merge(a,b):=a*b%m(部分木同士の場合の数は独立して考えられるので掛け算で求まる)
- add_root(a):=(a+1)%m(rootを含む部分木の全ての頂点が白の場合を考慮して+1)
- u->vに遷移するとき、頂点vが黒のときは sum_dp[u] 通り、頂点vが白のときは 1 通りであることから式を立てる
- e():=1(add_rootで+1されて白黒両方の場合の数になるため)
get_vにrootが白の場合の数が含まれている点に注意して、 -1した値を答えとして出力する。
https://atcoder.jp/contests/dp/submissions/49585048
W - Intervals
★解説AC★
in-place DP と 遅延セグ木。
$dp[i][j]:=$ $i$ 番目まで、最後に $1$ を立てたのが $j$ 文字目のときのスコアの最大値
これだと $dp$ 配列の空間計算量に $O(N^2)$ かかってしまうので、 以下のように in-place 化する。
$dp[i]:=$ 最後に $1$ を立てたのが $i$ 文字目のときのスコアの最大値
遷移式は、
- $dp[i]=max(dp[j])$ $(0 \le j < i)$
- $dp[j]=dp[j]+a_i$ $(l \le j \le i)$
更新の順番は $i=0,1,2,...$ で、 $r=i$ となるようなスコア $a_i$ がある場合に遷移式2を行う。
文字列をすべて $0$ にするとスコアは $0$ にできるので、 スコアは $0$ 以上になる点に注意。
https://atcoder.jp/contests/dp/submissions/49608858
X - Tower
★解説AC★
一見順列を考える必要がありそうで計算量的に厳しそう。 ただ、考察を進めると最適な並び順を決定することができる。
ほぼ解説を写経した。 (解説を見るのが一番わかりやすい)
https://atcoder.jp/contests/dp/submissions/49649052
Y - Grid 2
★解説AC★
包除原理。 解説がすべて。
https://atcoder.jp/contests/dp/submissions/49687223
Z - Frog 3
★解説AC★
Convex Hull Trick。 Dynamic-Li-Chao-Treeを拝借してACした。