Intro
单调队列优化 DP 需要状态变量 $j$ 与决策变量 $k$ 分离,而遇到交叉项如 $i\times j$ 时则无能为力。因此我们需要新的方法。
Example
【例题】玩具装箱
$$
\begin{align}
S_i&=\sum_{j\leq i}{C_i}+i\
f_{i, j}&=\min(f_{i - 1, k} + (S_j - S_k - L - 1)^2)\
f_{i, j}&=f_{i - 1,k} + (S_j - S_k - L-1)^2\
f_j&=f_k+S_j^2-2S_j(S_k+L+1)+(S_k+L+1)^2\
f_k+(S_k+L+1)^2&=2S_j\cdot S_k+(f_j+2(L+1)S_j-S_j^2)
\end{align}
$$
这里为了打消平方项的影响,我们直接把 $(S_k+L+1)^2$ 设置成了 $y$ 轴。
这根直线与凸壳相交,当且仅当这个点的下方的那条凸壳上的线段的斜率 $< k$ ,而上方这条 $ \geq k$。
方法
如果 $x_i$ 从小到大依次进来:此时只需维护半个凸壳。
- 将所给直线与凸壳上的点从左端开始进行对比,找到斜率介于两者之间的位置取出该位置的值作为
j
- 按照原始方程进行转移
- 维护凸壳,删除多余的点,将点 $(x_i, y_i)$ 从右端加入凸壳
需要注意的是,有时候按顺序插入的点不一定在凸壳的右侧,这时候需要维护整个凸壳,并多一个 $\log$ 来二分查找点的位置。
Code
1 | IL void init() { |
1 | IL Lf slope(int u, int v) { |