斜率优化 dp 学习笔记
先来看一道例题:
P3195 [HNOI2008]玩具装箱
首先考虑普通 dp。
设 $dp[i]$ 表示 $1\sim i$ 如何划分区间可以得到最小费用。
可以得到转移方程
$$dp[i] = \min_{j = 1} ^ {i} dp[j - 1] + (i - j - L + \sum_{k = i} ^ j C_k) ^ 2$$
通过前缀和优化,原方程简化为:
$$dp[i] = \min_{j = 1} ^ {i} dp[j - 1] + (i - j - L + s[i] - s[j - 1]) ^ 2$$
这是一个极其普通的 $\Theta(n^2)$ 方程。
注意到平方式,考虑斜率优化。
设 $p[i]=s[i]+i$。
有
$$ \begin{aligned} dp[i] &= \min_{j = 1} ^ {i} dp[j - 1] + ((s[i] + i) - (s[j - 1] + j - 1) - (L + 1)) ^ 2 \\ &= \min_{j = 1} ^ {i} dp[j - 1] + (p[i] - p[j - 1] - (L + 1)) ^ 2 \end{aligned} $$
考虑对于两个决策点 $j_1$ 和 $j_2$,$j_2$ 优于 $j_1$,所以有
$$ dp[j_1 - 1] + (p[i] - p[j_1 - 1] - (L + 1)) ^ 2 \ge dp[j_2 - 1] + (p[i] - p[j_2 - 1] - (L + 1)) ^ 2 $$
$$ dp[j_1 - 1] + (p[i] - (p[j_1 - 1] + L + 1)) ^ 2 \ge dp[j_2 - 1] + (p[i] - (p[j_2 - 1] + L + 1)) ^ 2 $$
拆开平方式,得到
$$ dp[j_1 - 1] + p[i]^2 + (p[j_1 - 1] + L + 1)^2 - 2\times p[i]\times (p[j_1 - 1] + L + 1) \ge dp[j_2 - 1] + p[i]^2 + (p[j_2 - 1] + L + 1)^2 - 2\times p[i]\times (p[j_2 - 1] + L + 1) $$
化简得
$$ 2\times p[i]\times (p[j_2 - 1] + L + 1) - 2\times p[i]\times (p[j_1 - 1] + L + 1) \ge (dp[j_2 - 1] + (p[j_2 - 1] + L + 1)^2) - (dp[j_1 - 1] + (p[j_1 - 1] + L + 1)^2) $$
设 $q[i] = (p[i] + L + 1)^2$。
$$ 2\times p[i]\times (p[j_2 - 1] - p[j_1 - 1]) \ge (dp[j_2 - 1] + q[j_2 - 1]) - (dp[j_1 - 1] + q[j_1 - 1]) $$
$$ 2\times p[i] \ge \dfrac{(dp[j_2 - 1] + q[j_2 - 1]) - (dp[j_1 - 1] + q[j_1 - 1])}{p[j_2 - 1] - p[j_1 - 1]} $$
设 $r[i] = dp[i] + q[i]$。
$$ 2\times p[i] \ge \dfrac{r[j_2 - 1] - r[j_1 - 1]}{p[j_2 - 1] - p[j_1 - 1]} $$
实际上因为我们前面的最基础的求和式子是 $1\sim i$ 取 $\min$ 的,如果想消掉这一堆 $-1$ 把最前面的范围改成 $0\sim i-1$ 就可以了。
只要满足这个式子,那么 $j_1$ 就是比 $j_2$ 优的。
右边是一个很像求斜率的东西。
放在几何的角度上,我们重新描述一遍这个东西:
对于两个点 $J_1(p[j_1 - 1], r[j_1 - 1])$ 和 $J_2(p[j_2 - 1], r[j_2 - 1])$,如果两点确定的直线的斜率 $\dfrac{r[j_2 - 1] - r[j_1 - 1]}{p[j_2 - 1] - p[j_1 - 1]} \le 2\times p[i]$ 时,$j_1$ 是更优的决策点。
画个图。
不同颜色的线段表示这些点的斜率为正的下凸壳。
图中绿色的直线代表 $2\times p[i]$。
此时我们的最优决策点 $j$ 就是图中绿色直线最靠近的蓝色点的位置。
这边给出了一种 $\Theta(n\log n)$ 的解法:考虑维护一个单调栈,对每个点 dp 完,与凸包的维护相同,然后二分。
当然我们想要的复杂度是 $\Theta(n)$ 的。
这里借鉴了该题第一篇题解的思路:
考虑维护单调队列。
取第一个 $\dfrac{r[j_2 - 1] - r[j_1 - 1]}{p[j_2 - 1] - p[j_1 - 1]} > 2\times p[i]$ 的点,也就是 head++
。操作结束得到的 head
即为最优决策。
然后算出 $dp[i]$。
这个时候要想把 $i$ 对应的点加入凸壳,就反复将队尾删去直到斜率满足条件为止。
考虑到每个点最多进一次出一次,时间复杂度 $O(n)$。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】