DP总结(四,斜率优化DP)

Fri Jan 10 2025
5 minutes

0.适用场景#

转移式形如 dpi=aibj+ci+djdp _ i = a _ i b _ j + c _ i + d _ j 的 DP 就可以使用斜率优化,因为 aibja _ i b _ j 这一项,单调队列优化不再适用。

1.原理#

设有转移方程 dpi=minj<i{dpj+(sumisumj+ij1L)2}dp _ i = \min _ {j \lt i} \{ dp _ j + (sum _ i - sum _ j + i - j - 1 - L) ^ 2 \},时间复杂度为 O(n2)\Omicron(n ^ 2),考虑优化。

先设 Si=sumi+1,l=L+1S _ i = sum _ i + 1,l = L + 1,为方便,我们先省去 min\min 的上下界,则有:

dpi=min{dpj+(SiSjl)2}dpi(Sil)2=min{dpj+Sj2+2Sj(lSi)}dp _ i = \min \{ dp _ j + (S _ i - S _ j - l) ^ 2 \} \Rightarrow dp _ i - (S _ i - l) ^ 2 = \min \{ dp _ j + S _ j ^ 2 + 2 S _ j(l - S _ i) \}

这个时候我们联想一次函数的解析式 y=kx+by = kx + b,变形得到 b=ykxb = y - kx,如果我们把每一个都看作变量,则 kxkx 是一个二元函数,这启发我们将和 i,ji,j 同时相关的设为 kxkx,只和一个变量相关的看作 y,by,b,一般我们设需要取最值的为 bb,也就是只与 ii 相关的设为 bb,则只和 jj 相关的设为 yy

又因为我们需要已知斜率,所以 kk 为二次项中与 ii 相关的,xx 为二次项中与 jj 相关的。并且,解析式为 b=ykxb = y - kx,所以一般 kk 值需要取负。

在本题中,我们可以做如下变量代换:

b=dpi(Sil)2y=dpj+Sj2k=2(lSi)x=Sj\begin{aligned} b &= dp _ i - (S _ i - l) ^ 2 y &= dp _ j + S _ j ^ 2 k &= -2(l - S _ i) x &= S _ j \end{aligned}

我们再将 (x,y)(x,y) 看作平面上的一个点,则题目转化为已知 kik _ i,求最小的 xj,yjx _ j,y _ j,使得 bib _ i 最小。

借用 OI-Wiki 的一张图:

可以发现,我们要做的就是沿着 yy 轴从下向上平移这条直线,使得第一个 (xj,yj)(x _ j,y _ j) 在该条直线上,这时 bib _ i 最小。同时,我们需要维护先前的决策点点集,并且我们发现,这个点集构成一个凸包,分如下情况讨论:

1.斜率与横坐标均单调#

我们维护一个队列 QQ,使得 i(head,tail),Slope(Qi1,Qi)<Slope(Qi,Qi+1)\forall i \in (head,tail),\text{Slope}(Q _ {i - 1},Q _ i) \lt \text{Slope}(Q _ i,Q _ {i + 1}),这里的 Slope\text{Slope} 表示斜率。

当我们找答案的时候,就是找到一个点 pp,使得 Slope(Qp1,Qp)k<Slope(Qp,Qp+1)\text{Slope}(Q _ {p - 1},Q _ p) \le k \lt \text{Slope}(Q _ p,Q _ {p + 1}),此时,点 QpQ _ p 就为最优决策点。

我们查询完答案后,我们首先要维护斜率的单调性,我们要使 Slope(Qtail1,Qtail)<Slope(Qtail,i)\text{Slope}(Q _ {tail - 1},Q _ {tail}) \lt \text{Slope}(Q _ {tail},i),弹出所有不满足的 QtailQ _ {tail},再插入这个点,就好了。

2.有不单调的#

这个时候就不满足单调队列的性质了,我们可以采取以下方法来维护这个凸包

弹队首变为找到一个最小的 pp 使得上面的式子成立,可以用二分实现。

对于插入操作就不那么好维护了,我们可以使用两种方法维护这个凸包:

(1) 平衡树#

我们直接用平衡树来维护这个凸包,上面的二分操作就可以在平衡树上二分了。

可以不用手写,直接用 set 就行

(2) CDQ 分治#

我不会,看 OI-Wiki 得了

2.更高阶的#

我们发现,其实我们没必要对式子变形。

我们重新看原来的方程:

dpi=min{dpj+Sj2+2Sj(lSi)}+(Sil)2dp _ i = \min \{ dp _ j + S _ j ^ 2 + 2 S _ j(l - S _ i) \} + (S _ i - l) ^ 2

发现,我们的瓶颈就是在求 min\min 里面的式子。

我们沿用一次函数的模型来解决。但这次,我们的变量代换就不太一样了。

我们沿用二次项是与 i,ji,j 都有关的思路,但是,我们考虑代入求值。则与 ii 有关的是已知的,设为 xx,与 jj 有关的设为 jjmin\min 中只与 jj 有关的设为 bb,则变量代换如下:

x=Sik=2Sjb=dpj+2lSjy=dpi(Sil)2\begin{aligned} x &= S _ i k &= -2 S _ j b &= dp _ j + 2 l S _ j y &= dp _ i - (S _ i - l) ^ 2 \end{aligned}

则问题转变为求一些一次函数在 x=Six = S _ i 处的极值,同时支持插入线段,这个可以用李超线段树来方便的维护。

并且代码比平衡树与 CDQ 分治短得多