学习笔记——斜率优化 dp
引入#
斜率优化,是单调队列优化的一个进阶版本,为了更好地理解,先来回顾一下单调队列吧~
所谓单调队列优化,就是对于形如:
的 式,我们把所有的 放进单调队列里,实现 的转移。
这个时候,只有在式子中,每一项只有关于 或者只有关于 的。但是如果有这样一个式子:
这时候,我们就不能只考虑 ,因为对于每个 ,其大小都是不同的。
流程#
我们先来看一道例题:[HNOI2008]玩具装箱
我们很容易得到原始的 式子, 是前缀和:
为了简化,我们设 ,。
则可以转化为:
我们可以发现其中有一项 ,不能用单调队列。
这时候,我先把式子移项成:
其中 项都是已知的,我们需要从中找出使得 最小的。
不妨,我们把 看成 , 看成 。那么这个式子可以看成是一条直线,而其斜率是固定的 ,截距就是 。并且,这条直线必然经过点 。这时候,我们回来考虑我们的目的:求使得 最小。这也就是说要使截距最小,而斜率是确定的,我们可以看成是一条直线可以上下平移。
如果我们把之前已经求出的化成一个个点,其横坐标是 ,其纵坐标是 ,此时只要这条直线经过了这个点,那么也就是说当前的截距加上 就是从当前的 转移所得到的 。为了使得 最小,我们找到从下往上第一个经过这条直线的点转移即可。
有点绕,我们来看几张图:
然后我们用当前的直线从下往上移,当碰到第一个点时就停下转移:
此时得到的 是最小的。
然后我们发现,斜率 是单调递增的,那么一个点一旦不满足,那么对于之后的直线也一定不会选它了,我们可以用单调队列来维护斜率。这样,我们也可以用类似于单调队列的方式来维护斜率,实现 转移。
接下来,我分享我的套路:
- 写出原始的 式子;
- 然后把只含有 项的放在右边,其他都移到左边;
- 接下来把既含有 又含有 的项中的 项看成 ,右边看成 ;
- 然后观察斜率是否满足单调性,若满足,则可以用单调队列,否则用二分;
- 最后考虑维护上凸还是下凸。
好了。
Code#
#include<bits/stdc++.h>
#define inf 1<<30
#define INF 1ll<<60
#define ll long long
using namespace std;
const int MAXN=5e5+10;
ll a[MAXN],b[MAXN],c[MAXN],dp[MAXN];
int q[MAXN];
ll X(int i){return 2*b[i];}
ll Y(int i){return dp[i]+b[i]*b[i];}
int main()
{
int n,L;
scanf("%d%d",&n,&L);
for(int i=1;i<=n;i++){
scanf("%lld",&c[i]);
c[i]+=c[i-1];
a[i]=c[i]+i;b[i]=c[i]+i+1+L;
}
int head=0,tail=0;
b[0]=L+1;
for(int i=1;i<=n;i++){
while(head<tail&&a[i]*(X(q[head+1])-X(q[head]))>(Y(q[head+1])-Y(q[head])))
head++;
int j=q[head];
dp[i]=dp[j]+(a[i]-b[j])*(a[i]-b[j]);
while(head<tail&&(Y(i)-Y(q[tail]))*(X(q[tail])-X(q[tail-1]))<(Y(q[tail])-Y(q[tail-1]))*(X(i)-X(q[tail])))
tail--;
q[++tail]=i;
}
printf("%lld\n",dp[n]);
}
/*ZMatrisutedX
dp[i]=dp[j]+(c[i]+i-c[j]-j-L)^2
a[i]->c[i]+i b[i]->c[i]+i+L
2*b[j]*a[i]+dp[i]-a[i]^2=dp[j]+b[j]^2
*/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?