线性dp小总结
前言
2020暑假,回归OI。这两个dp难度比较低,但有一定价值,写个归纳总结。
线性dp小总结(优化)
洛谷P4933 大师
看懂题目后,容易列出dp方程:
- \(f(i,j)\) 表示以 \(i\) 结尾,公差为 \(j\) 的等差数列方案数。
\[f(i,j) = \sum_{\{k | h_i - h_k = j\}} f(k,j)
\]
状态是 \(O(n^2)\) 的,转移是 \(O(n)\) 的,我们必须有一些优化。发现转移就是要对 \(i\) 前面所有满足 \(h_k = h_i - j\) 的 \(f(k,j)\) 求和。
于是我们枚举公差 \(j\):
-
令函数 \(g(x) = \sum_{\{k|h_k=x,k<i\}} f(k,j)\)
-
则有 \(f(i,j) = g(h_i-j)\)
\(g(x)\) 可以在dp的过程中累积,转移便优化成了 \(O(1)\)
总结:对于dp转移过程中如果遇见了求和,试着发现求和式子的规律,设计函数(并且该函数可以在dp过程中累积),从而降低转移的复杂度。
洛谷 P5858 「SWTR-03」Golden Sword
看懂题目后,容易列出dp方程:
- \(f(i,j)\) 表示以 \(i\) 结尾,当前原材料为 \(j\) 的最大耐久度
\[f(i,j) = \max_{j-1 \le k \le j+s} \{ f(i-1,k) \} + a_i*j
\]
状态是 \(O(n^2)\),转移是 \(O(n)\),我们必须有一些优化。试着模拟 \(j\) 的枚举,发现 \(j\) 在 \(0 \le j \le w\) 移动的过程中 \([j-1,j+s]\) 也在向右移动。我们需要的就是这个移动区间的最大值。至此,我们发现这个转移可以使用单调队列实现 \(O(1)\) 转移。
如果在dp转移过程中遇见了求最值,试着发现最值区间的变化规律,尝试利用数据结构优化,从而降低转移的复杂度。