[笔记] DP 优化

斜率优化

原理

平面上 \(n\) 个点 \((x_i, y_i)\),任意给出 \(a, b\),则 \(ax_i+by_i\) 的最大值,最小值均在 \(n\) 个点构成的凸包上。

\(ax_i+by_i=c\),转成 \(-by_i=ax_i-c\),求 \(c\) 的最值。

就是求斜率为 \(a\) 的,经过 \((x_i,-by_i)\)\(y\) 轴上截距取到最值的那个点。

\(y\) 坐标乘上 \(b\),对于一个点是否在凸包上,并不影响。

因此,如果状态转移方程可以写成 \(y=ax+b\) 的形式则可以试用斜率优化。

或者说,假设 dp 转移方程需要枚举一维 \(j\),并且能通过包括移项等一系列操作化成 \(y(j)=kx(j)+b\),其中 \(k, b\) 是常数的形式,则可以使用斜率优化.

例子

以 [SDOI2016] 征途 为例,阐述如何实现。

\(S_i=\sum_{j=1}^ia_j\),对于方差式子的转换见这个,得到 \(m\sum_{i=1}^mb_i^2-S_n^2\)

\(f(i, j)\) 表示将前 \(i\) 个数分成 \(j\)\(\sum_{k=1}^jb_k^2\) 的最小值,则

\[f(i, j) = f(k, j-1)+(s_i-s_k)^2 \]

这样化成 \(y=kx+b\) 的形式得

\[f(k,j-1)+S_k^2=2S_iS_k+f(i,j)-S_i^2 \]

这是标准的斜率式 \(y(k) = k\times x(k)+b\),然后分析维护方式和维护上/下凸包.

\[k=S_i,x(k)=S_k,b=f(i,j)-S_i^2 \]

因为 \(k,x(k)\) 都是递增的,直接单调队列维护即可。

同时因为 \(f(i,j)\)\(b\) 中为正,要求最小值,所以维护下凸包。

\(k,x(j)\) 的单调性

  • \(k,x(j)\) 都单调:[HNOI2018] 玩具装箱

    • 使用单调队列维护。
  • \(k\) 不单调,\(x(j)\) 单调:[SDOI2012]任务安排

    • 使用单调队列维护,转移在单调队列上二分
  • \(k,x(j)\) 不单调:[NOI2007] 货币兑换

    • CDQ 分治、李超树维护,推荐。

      前者需要离线,但用处更广泛。

      后者可以应付强制在线,但如果只能从一个区间转移,比平衡树多一个 \(\log\)

    • 分块,在李超树 \(\log^2\) 的情况下,也许可以选择每块维护一个凸包,有时候因为常数问题,两个 \(\log\) 和根号速度差不多。

    • 平衡树、set 维护,不太推荐,难写。

  • \(k\) 单调,\(x(j)\) 不单调:没见过。

其他习题

YZOJ 1767 [Ceoi2009]harbingers

YZOJ 70107 保护

Slope Trick:解决一类凸代价函数的DP优化问题

当序列 DP 的转移代价函数满足

  • 连续;
  • 凸函数;
  • 分段线性函数.

时,可以通过记录分段函数的最右一段 \(f_r(x)\) 以及其分段点 \(L\) 实现快速维护代价的效果。

如:

\[f(x)= \begin{cases} -x-3 & (x \le -1) \\ x &( -1 < x\le1)\\ 2x-1 &(x > 1)\end{cases} \]

可以仅记录 \(f_r(x)=2x-3\) 与分段点 \(L_f=\{-1,-1,1\}\) 来实现对该分段函数的存储。

注意:要求相邻分段点之间函数的斜率差为 \(1\) ,也就是说相邻两段之间斜率差 \(>1\) 的话,这个分段点要在序列里出现多次。

优秀的性质:

\(F(x),G(x)\) 均为满足上述条件的分段线性函数,那么 \(H(x)=F(x)+G(x)\) 同样为满足条件的分段线性函数,且 \(H_r(x)=F_r(x)+G_r(x),L_H=L_F\cup L_G\)

该性质使得我们可以很方便得运用数据结构维护 \(L\) 序列。

例题

CF713C Sonya and Problem Wihtout a Legend [ ]
CF1534G [ ]
原文地址:https://www.cnblogs.com/IrisT/p/15720831.html