【学习笔记】Slope Trick
Slope Trick
Slope Trick 是一种优化 DP 的方法,核心思想是通过存储DP转移的一些关键信息(如分段函数的分段点和最左/右边的一段函数)从而利用数据结构高效维护转移。(不是斜率优化DP)
接下来都以凸函数,维护最左边的函数为例
注:图中所画斜率有小于 的只是为了好看,实际题目的斜率一定为整数
一般可以使用 Slope Trick 优化的DP方程有以下要求:
- 是连续的
- 是分段一次函数
- 是凸函数(斜率单调不升,图像上凸)或凹函数
分段一次凸函数具有非常优秀的性质:
-
两个凸函数相加还是凸函数
设凸函数 和 ,其分段点集合分别为 和 ,其最右端的函数分别为 和 ,则 也是凸函数,分段点集合满足 ,。 -
凸函数加一次函数还是凸函数
这样我们将所有斜率减少(增加) 的位置放到数据结构里面维护,也就是说如果一个地方的斜率变化大于 就加多次。
如函数
图像为
我们维护最左边的图像信息 和分段点集合 ,其中 这个位置加了两次
再如绝对值函数(凹函数) ,维护 和分段点集合 。
事实上每一个分段一次凸函数都可以这样表示,我们就可以快速维护许多函数操作。
几种常见的函数操作:
-
相加:
直接最左边图像 相加,分段点集合合并。 -
找最大/小值:
就是斜率为零的那一段,用大根堆 维护其左边的所有分段点, 维护右边的,始终保证 ,其余点扔进 。
堆顶即为最大值的左端点和右端点。 -
加一次函数
例如加上一个 ,就只用把 堆顶的第一个元素扔到 里面
如果加的一次函数斜率较大,为了保证复杂度,修改集合的定义为每个位置的斜率变化量即前/后缀差分,修改 即可。 -
前后缀max:
前缀 就是直接扔掉 里的所有点,后缀就是扔掉 里的所有点。 -
平移:
只用维护 的变化,分段点打平移标记。 -
翻转:
只用维护 的变化,分段点打翻转标记。
答案统计的时候有两种方法,一种是还原图像,另一种是记录决策点(一般是斜率为零的线段端点)
例题:CF713C
给定一个有 个正整数的数组,一次操作中,可以把任意一个元素加一或减一。(元素可被减至负数或 ),求使得原序列严格递增的求最小操作次数。
首先把严格递增转化为单调不降,只需令 ,然后就是线性 DP
令 ,,改写成函数的形式,则转移方程就是
发现这是个斜率单调不降的凹函数:
首先 这是个凹函数,然后 是个前缀

凹函数加凹函数,所以 也是凹函数。
所以状态转移其实就是维护凹函数相加和取前缀 两个操作,这很 Slope Trick,发现 的图像最后一段一定是平的,所以我们只需要维护斜率小于零的大根堆 。
加入绝对值函数 ,相当于在集合中加入元素 ,分类讨论 的位置:
- 当 时,加的第二个 实际斜率是 ,取前缀 时又删除了,所以此时只用加一个 。

- 当 时,先加入 , 的斜率从 变成 ,取前缀 时需要删除,所以 出去。

这样我们同时完成了凹函数相加和取前缀 操作。
这道题有个很好的性质就是你每次决策点就是堆顶,所以直接累加答案,这道题就做完了。
四倍经验:CF713C,CF13C,P2893,P4597,注意是严格非降还是严格上升
Code:
priority_queue<int> q; main(){ int ans=0; int n;cin>>n; for(int i=1;i<=n;i++){ int x; cin>>x; x=x-i; q.push(x); if(x<q.top()){ q.push(x); ans+=q.top()-x; q.pop(); } } cout<<ans<<endl; }
本文来自博客园,作者:CCComfy,转载请注明原文链接:https://www.cnblogs.com/cccomfy/p/17743031.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!