整理:斜率优化
关于斜率优化的整理
我们先来看一道题。
题目描述
P 教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。
P 教授有编号为 \(1 \cdots n\) 的 \(n\) 件玩具,第 \(i\) 件玩具经过压缩后的一维长度为 \(C_i\)。
为了方便整理,P 教授要求:
-
在一个一维容器中的玩具编号是连续的。
-
同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物。形式地说,如果将第 \(i\) 件玩具到第 \(j\) 个玩具放到一个容器中,那么容器的长度将为 \(x=j-i+\sum\limits_{k=i}^{j}C_k\)。
制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为 \(x\),其制作费用为 \((x-L)^2\)。其中 \(L\) 是一个常量。P 教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过 \(L\)。但他希望所有容器的总费用最小。
数据范围与约定
对于全部的测试点,\(1 \leq n \leq 5 \times 10^4\),\(1 \leq L \leq 10^7\),\(1 \leq C_i \leq 10^7\)。
这显然是一道 DP 题,状态容易得出,\(dp_i\) 表示装下前 \(i\) 个玩具的最小花费。
转移就是将若干个玩具作为一段装起来,\(dp_i=dp_j+(\sum_{k=j+1}^i c_k-L)^2\),显然利用前缀和优化求和过程,因此转移方程写为:
\(dp_i=dp_j+(pre_i-pre_j-L)^2\)。
拆开式子:\(dp_i=dp_j+pre_i^2+pre_j^2+L^2-2pre_ipre_j-2pre_iL+2pre_jL\)
这看起来无法使用常规手段优化,因为式子比较复杂,有些项与 \(i,j\) 均相关,无法使用单调队列优化。
但是我们对式子进行简单变形:
我们将 \(dp_j+pre_j^2+2pre_jL\) 设为 \(y\),\(2pre_i\) 设为 \(k\),\(pre_j\) 设为 \(x\),\(dp_i+2pre_iL-prei^2-L^2\) 设为 \(b\).
那么上面的式子就变成了 \(y=kx+b\),即一次函数。
现在问题就变成了平面上有若干个点 \((x,y)\),现在使用一条斜率为 \(k\) 的直线去分别经过这些点,求截距的最小值。
看上去还是无法解决。
但是这里我们有一个计算几何的工具:凸包[1]。
所以我们对前面所有点维护下凸包,然后二分求切点即可。
而上面我们设出一次函数解析式,维护凸包,二分切点并最后进行转移的过程,就是所谓斜率优化。你问我为什么叫斜率优化?我也不知道。
斜率优化的基本过程
- 定义状态并写出转移方程。
- 化简式子并设出一次函数解析式。
- 套模版维护凸包。
- 二分求出切点,即转移位置。
- 转移。
- A 掉这道题
过程简单地如同如何将大象塞进冰箱。
实现细节
注意可以转移的区域,即可行决策点,当决策点不合法时要从凸包中删去。
二分时,定义 \(cal(i,j)\) 表示使用 \(j\) 这个决策点转移 \(i\),然后用 \(mid\) 和 \(mid+1\) 比哪个更优即可。

浙公网安备 33010602011771号