【DP】Educational DP Contest

HinanawiTenshi發表於2021-10-11

這份 dp 題單的最後幾題好難 orz。

前面的題比較簡單,所以我會選取一些題來講,其它的直接看程式碼理解吧 qwq。

傳送門:

https://atcoder.jp/contests/dp

全部 AC 程式碼:

https://atcoder.jp/contests/dp/submissions?f.Task=&f.LanguageName=&f.Status=AC&f.User=HinanawiTenshi

E

這道題不同於常規的揹包問題,因為揹包容量很大,我們不能對容量進行 dp,但注意到全部的收益加起來不超過 \(10^5\),想到用 \(f(j)\) 表示收益至少為 \(j\) 時的最小容量花費。記當前在第 \(i\) 個物品,有狀態轉移方程:

\[f(j) = \min(f(j), f(j-v_i)+w_i) \]

J

注意到每碟壽司數量最多 \(3\) 個,不難想到用 \(f(x, y, z)\) 表示當前有 \(x\) 盤壽司數量為 \(3\)\(y\) 盤壽司數量為 \(2\)\(z\) 盤壽司數量為 \(1\) 時距離吃完全部壽司的期望步數

根據全期望公式,我們有:

\[f(x, y, z) = (1-\frac{x+y+z}{n})f(x, y, z) + \frac{x}{n}f(x-1, y+1, z) + \frac{y}{n}f(x, y-1, z+1) + \frac{z}{n}f(x, y, z-1) \]

根據上述公式進行記憶化搜尋即可,細節見程式碼。

L

注意到 \(X + Y = sum\)\(sum\) 是總分數),\(X - Y = 2X - sum\),所以 Taro 的目標是最大化 \(X\)Jiro 的目標是最小化 \(X\)

\(dp(l, r, op)\) 表示 \([l, r]\) 區間輪到某玩家(\(op = 1\) 表示輪到 Taro,否則表示輪到 Jiro)決策時 Taro 的最高得分。

\(op = 1\) 時,\(dp(l, r, op) = \max(dp(l+1, r, 0) + w_l, dp(l, r-1, 0)+w_r)\)

\(op = 0\) 時,\(dp(l, r, op) = \min(dp(l+1, r, 0), dp(l, r-1, 0))\)

M

\(f(i, j)\) 表示前 \(i\) 個小孩共分了 \(j\) 個蠟燭的方案數,以給第 \(i\) 個小孩多少個蠟燭為狀態劃分依據。

有方程:\(f(i, j) = \sum_{k = \max(0, j-w_i)} ^ j f(i-1, k)\)

直接轉移顯然會超時,所以我們在更新 \(f\) 的同時維護一個字首和 \(s\)\(s(i, j) = \sum_{k=1}^j f(i, k)\)

O

\(f(i, st)\) 表示前 \(i\) 個男人和對應子集為 \(st\) 的女人匹配的方案數。

考慮狀態轉移:

現在已經有 \(i-1\) 個男人以及相應匹配的子集為 \(st\) 的女人集合,當新加入一個男人的時候,對於可以和他配對的女人 \(j\)(而且需要滿足這個女人不在 \(st\) 中),我們有狀態轉移:\((i-1, st)\rightarrow (i,st\cup j)\)

因此有這樣的更新 \(f\) 的方式:\(f(i, st\cup j) += f(i-1, st)\)

R

倍增 Floyd(是之前沒聽說過的東西呢

\(g(i, j)\) 為讀入的矩陣,\(f(k, i, j)\) 為經過 \(k\) 條邊,從 \(i\rightarrow j\) 的方案數。

那麼我們有 \(f(k, i, j) = \sum_{u = 1}^n f(k-1, i, u) \times g(u, j)\)

如果看不出有什麼性質,那我將上面的子換個寫法:

\[f_k(i, j) = \sum_{u = 1}^n f_{k-1}(i, u) \times g(u, j) \]

注意到,這正是矩陣乘法的形式!也就是:\(f_k = f_{k-1}\times g\)

而且可以發現,\(g\) 恰好為 \(f_1\),我們有 $$f_k = f_{k-1}\times f_1$$。

所以答案為 \(f_1^K = g^K\),用矩陣快速冪加速這個過程就好了。

S

數位 dp。

\(f(i, j, k)\) 表示區間 \([1, \overline{j99...999}]\)\(\overline{j99...999}\)\(i\) 位,首位為 \(j\) ),滿足十進位制意義下數位和 \(mod~D\)\(k\) 的數的個數。

  • 對於 \(j = 0\)\(f(i, j, k) = f(i-1, 9, k)\)
  • 對於 \(j\neq 0\)\(f(i, j, k) = f(i, j-1, k) + [j \equiv k \pmod D] + f(i-1, 9, k-j\pmod D)\)

T

思路比較新穎的 dp。

\(f(i, j)\) 表示對於前 \(i\) 個位置,末位值為 \(j\),值域為 \([1, i]\)合法排列數。

合法就是滿足題目中所給的大小關係。

考慮從 \(i-1\rightarrow i\) 的轉移、統計:

我們所需要統計的就是 \([1,i]-\{j\}\) 這個值域內有多少個(長度為 \(i-1\) 的)排列是合法的。

如果 \(i-1,i\) 需要滿足的關係為 \(<\) ,那麼我們有 \(f(i, j) = \sum_{k=1}^{j-1}f(i-1, k)\),因為在引入 \(j\) 後,原先合法的長為 \(i-1\),結尾為 \(k\) 的排列在 \([1, i]\) 依然是合法的。

類似地,如果 \(i-1,i\) 需要滿足的關係為 \(>\), 有 \(f(i, j) = \sum_{k=j}^{i-1}f(i-1, k)\)

一個直觀的理解是,當插入 \(j\) 時,\([1, i-1]\) 的每個排列中所有 \(\geq j\) 的數都加了 \(1\),變換前後的合法方案是一一對應的。

U

\(f(S)\) 表示集合 \(S\) 按在分組後可以得到的最大貢獻。

我們不妨記 \(U\) 代表全集,那麼答案就是 \(f(U)\)

以分出一組 \(S\) 的子集 \(S0\) 作為劃分依據,有狀態轉移方程 \(f(S) = \max (f(S-S0) + cal(S0))\)

\(cal(S0)\) 代表子集 \(S0\) 為同一組時的貢獻值。

如果在求取每個狀態的時候計算 \(cal\),那麼時間複雜度為 \(O(3^nn^2)\),無法承受。

所以可以預處理一下所有子集的 \(cal\) 值。

這樣做的時間複雜度為 \(O(2^n n^2 + 3^n)\)

V

換根 dp。

有點噁心的一題

記點 \(u\) 的合法方案數為 \(f(u)\)\(u\) 只向子樹擴充套件的合法方案數為 \(f'(u)\)

對於點 \(u\),有 \(f(u) = \prod (1 + f'(ch)) \times (1 + \frac{f(fa)}{f'(u)})\)

\(ch\) 代表 \(u\) 的子節點,\(fa\) 代表 \(u\) 的父節點。

因為給出的數不保證存在逆元,因此需要處理出每個點子節點對應的 \(f'\) 值的字首積字尾積

W

個人感覺這道題是這份題單中最難的了 QAQ。

\(f(i)\) 表示前 \(i\) 個位置做出決策後而且第 \(i\) 個決策為 1 所能得到的最大價值。

我們記區間為三元組 \((l, r, v)\),編號為 \([1, m]\)

有轉移方程:\(f(i) = max(f(j)+\sum v_k)\),其中 \(k\) 為滿足 \(l\in(j,i],r\geq i\) 的區間編號。

我們考慮優化:

對於當前數軸上的位置 \(i\),假設它處於一個 \([l, r]\)區間中,那麼我們可以將這個區間的值 \(v\) 加到數軸上的 \([0,l-1]\) 中,那麼在統計的時候,只需要統計數軸\([0,i-1]\) 的最大值就可以得到 \(f(i)\) 的值了。

位置 \(i\) 處於多個區間的情況類似。

然後我們對數軸上的點 \(i\) 進行更新。

用什麼可以高效維護上述數軸上的操作呢?線段樹可以做到,也就是區間加以及區間最大值查詢

X

排序 + dp。

考慮從上到下相鄰的兩個物品 \(i, i+1\) 的屬性滿足怎麼樣的關係是最優的排列方式。

所謂最優,就是交換這兩個物品的相對位置之後,能夠承載上面的物品的重量不比原來的位置好。

也就是 \(\min(s_i, s_{i+1}-w_i)\geq \min(s_{i+1}, s_i-w_{i+1})\)

下面尋找上式的等價條件:

因為 \(s_i\geq s_i-w_{i+1}\geq \min(s_{i+1}, s_i-w_{i+1})\),因此上式等價於:\(s_{i+1}-w_i\geq\min(s_{i+1}, s_i-w_{i+1})\)

類似地,\(s_{i+1}\geq s_{i+1}-w_i\),故上式進一步等價於:\(s_{i+1}-w_i\geq s_i-w_{i+1}\),也就是 \(s_i+w_i\leq s_{i+1}+w_{i+1}\)

至此,我們找到了排序依據。

事實上,直接用 \(\min(s_i, s_{i+1}-w_i)\geq \min(s_{i+1}, s_i-w_{i+1})\) 作為排序依據亦可。

剩下的工作變成揹包問題。

\(f(i, j)\) 為前 \(i\) 個物品,選取了重量和至多為 \(j\) 的物品的最大收益。

有轉移方程:\(f(i, j) = \max (f(i-1, j-w_i)+v_i, f(i-1, j))\),然後列舉的 \(j\) 的範圍是 \([w_i, w_i + s_i]\)

與揹包問題一樣,可以減少一維空間。

Y

組合計數 dp。

直接轉移有 \(n^2\) 個狀態,直接去世。

但是障礙很少,所以可以從障礙入手。

我們記 \(f(x, y)\) 為從 \((1, 1)\) 出發不經過任何一個障礙到達 \((x, y)\) 點的方案數。

那麼我們有 \(f(x, y) = C_{x+y-2}^{x-1}-\sum C_{x-X+y-Y}^{x-X} f(X, Y)\)​,其中 \((X,Y)\)​ 為障礙點且 \(X<x,Y<y\)​。

統計答案和上面的求 \(f(x, y)\) 完全一樣,把 \((n, m)\) 看成是障礙點即可。

Z

斜率優化 dp。

\(f(i)\) 為跳到 \(i\) 的最小花費。

顯然,轉移方程:\(f(i) = \min (f(j)+(h_i-h_j)^2) + c\),其中 \(j\in[1, i-1]\)

我們假設決策點為 \(j\),那麼有 \(f(i) = f(j) + h_i^2 - 2h_ih_j + h_j^2 + c\)

進一步將上式化為:\(f(j) + h_j^2 = 2h_ih_j + f(i) + c - h_i^2\)

我們記 \(y = f(j) + h_j^2, k=2h_i,x=h_j, b=f(i)+c-h_i^2\)

那麼這正好為 \(y = kx + b\) 的形式。

我們的目標是最小化 \(f(i)\),這等價於最小化 \(b\),也就是從維護的下凸殼中找到使直線的 \(b\) 最小的點即可。

對斜率優化不熟悉可以看看這個:https://www.cnblogs.com/Tenshi/p/14481908.html