斜率优化
例题引入
朴素的 DP 做法
令
状态转移方程:
其中
该做法的时间复杂度为
优化
考虑简化上面的状态转移方程式:令
将与
考虑一次函数的斜截式
则转移方程就写作
如图,我们将这个斜率为
容易发现,可能让
具体地,设
我们维护一个指针
在插入一个点
这样我们就将 DP 的复杂度优化到了
概括一下上述斜率优化模板题的算法:
- 将初始状态入队。
- 每次使用一条和
相关的直线 去切维护的凸包,找到最优决策,更新 。 - 加入状态
。如果一个状态(即凸包上的一个点)在 加入后不再是凸包上的点,需要在 加入前将其剔除。
接下来我们介绍斜率优化的进阶应用,将斜率优化与二分/分治/数据结构等结合,来维护性质不那么好(缺少一些单调性性质)的 DP 方程。
二分/CDQ/平衡树优化 DP
当我们在
在上述例题中,直线的斜率随
玩具装箱 改
有
本题与「玩具装箱」问题唯一的区别是,玩具的价值可以为负。延续之前的思路,令
状态转移方程:
其中
将方程做相同的变换
然而这时有两个条件不成立了:
- 直线的斜率不再单调;
- 每次加入的决策点的横坐标不再单调。
仍然考虑凸壳的维护。
在寻找最优决策点,也就是用直线切凸壳的时候,我们将单调队列找队首改为:凸壳上二分。我们二分出斜率最接近直线斜率的那条凸壳边,就可以找到最优决策。
在加入决策点,也就是凸壳上加一个点的时候,我们有两种方法维护。
第一种方法是直接用平衡树维护凸壳。那么寻找决策点的二分操作就转化为在平衡树上二分,插入决策点就转化为在平衡树上插入一个结点,并删除若干个被踢出凸壳的点。此方法思路简洁但实现繁琐。
下面介绍一种基于 CDQ 分治 的做法。
设
我们先调用
算出 。然后我们对 这个区间内的决策点建凸壳,然后使用这个凸壳去更新 。这时我们决策点集是固定的,不像之前那样边计算 DP 值边加入决策点,那么我们就可以把 的 先按照直线的斜率 排序,然后就可以使用单调队列来计算 DP 值了。当然,也可以在静态凸壳上二分计算 DP 值。对于
中的每个点,如果它的最优决策的位置是在 这个区间,在这一步操作中他就会被更新成最优答案。当执行完这一步操作时,我们发现 中的所有点已经发挥了全部的作用,凸壳中他们存不存在已经不影响之后的答案更新。因此我们可以直接舍弃这个区间的决策点,并使用 解决右区间剩下的问题。
时间复杂度
对比「玩具装箱」和「玩家装箱 改」,可以总结出以下两点:
- 二分/CDQ/平衡树等能够优化 DP 方程的计算,于一定程度上降低复杂度,但不能改变这个方程本身。
- DP 方程的性质会取决于数据的特征,但 DP 方程本身取决于题目中的数学模型。
小结
斜率优化 DP 需要灵活运用,其宗旨是将最优化问题转化为二维平面上与凸包有关的截距最值问题。遇到性质不太好的方程,有时需要辅以数据结构来加以解决,届时还请就题而论。
习题
- 「SDOI2016」征途
- 「ZJOI2007」仓库建设
- 「APIO2010」特别行动队
- 「JSOI2011」柠檬
- 「Codeforces 311B」Cats Transport
- 「NOI2007」货币兑换
- 「NOI2019」回家路线
- 「NOI2016」国王饮水记
- 「NOI2014」购票
build本页面最近更新:2022/4/20 20:21:30,更新历史
edit发现错误?想一起完善? 在 GitHub 上编辑此页!
people本页面贡献者:Enter-tainer, StudyingFather, Ir1d, luoguyuntianming, Marcythm, sshwy, wood3, abc1763613206, BackSlashDelta, billchenchina, Chrogeek, ChungZH, fps5283, GavinZhengOI, greyqz, GreyTigerOIer, Henry-ZHR, hsfzLZH1, Konano, Luckyblock233, MrFoodinChina, ouuan, Xeonacid
copyright本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用