這份 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\) 個物品,有狀態轉移方程:
J
注意到每碟壽司數量最多 \(3\) 個,不難想到用 \(f(x, y, z)\) 表示當前有 \(x\) 盤壽司數量為 \(3\),\(y\) 盤壽司數量為 \(2\),\(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 = 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