单调队列优化dp & 斜率优化dp
ko no SB da!!!
单调队列优化dp
对于方程
f[i]=min(f[j]+b[j]+a[i]) i-m<j<i
其中a,b为只与i和j有关的函数
显然可以转化为
f[i]=min(f[j]+b[j])+a[i] i-m<j<i
可以考虑用单调队列优化
以min为例,维护一个单调递增的队列,即队首是最小值,与单纯的单调队列用法相同。
for(int i=1;i<=n;++i){
while(!q.empty() && q.front()<=i-m)q.pop_front();//弹出过期元素
int j=q.front();
f[i]=f[j]+b[j]+a[i];
while(!q.empty() && f[q.back()]+b[q.back()]>f[i]+b[i])q.pop_back();//维护单调性
q.push_back(i);
}
一些题目
斜率优化dp
单调队列优化dp中的项至于i(当前状态),或j(决策点)有关,斜率优化dp则一般与 i*j 有关
对于方程
f[i]=min(a[i]+b[j]+c[i]*d[j]) j<i
任取决策点k,j (0<k<j<i)
如果j优于k,则有
a[i]+b[k]+c[i]*d[k]>a[i]+b[j]+c[i]*d[j]
两边消去,并移项得
c[i]*(d[k]-d[j])>b[j]-b[k]
假设d单调递增(题设),即
左右同时除以
c[i]<(b[j]-b[k])/(d[k]-d[j])
由于单调递增(题设),如果此时j不如k,以后也一定不如k,那么就可以把j舍弃,用单调队列实现
左右同时乘
-c[i]>(b[k]-b[j])/(d[k]-d[j])
令,不等式右侧可以看作一个斜率式,令,则如果要把队首舍弃,则要满足
-c[i]>slope(q[head],q[head+1])
一定要清楚slope是如何定义的
另外,为了避免出现分母为零的情况,要满足
考虑维护队列的单调性
对于相邻的三项 ,如果斜率单调递减,则有 ,假设 ,那么一定有 ,只要有元素出队那么队列会清空(维护了个寂寞),所以要满足斜率单调递增(视情况而定)
head=1,tail=1;
for(int i=1;i<=n;++i){
while(head<tail && -c[i]>slope(q[head],q[head+1]))head++;
int j=q[head];
f[i]=a[i]+b[j]+c[i]*d[j];
while(head<tail && slope(q[tail-1],q[tail])>slope(q[tail],i))tail--;
q[++tail]=i;
}
还有一种几何意义上的理解方法,真正的用直线的斜率来证明,队列维护出来的是一个下凸包
(本蒟蒻并不会)
一些题目
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库