「Note」DP 方向 - DP 优化
1. 单调队列优化 DP
1.1. 简介
当一个选手比你小还比你强,你就打不过他了。这是对单调队列简单形象的概括。
单调队列在转移的过程中不断排除不可能成为决策点的元素,使每次转移寻找决策点的时间复杂度降为
其中需要满足
不难发现单调队列要维护的是
此时取队头元素,它一定满足在范围内最优,将其作为决策点即可。特殊地,有时需要特判队列为空的情况。
1.2. 常见技巧
大部分情况下,转移方程并不显著,因为在其中的贡献往往与
1.3. 例题
(单调队列优化多重背包)
物品 |
物品 |
物品 |
前 |
显著地,有以下转移方程:
设
不难想到在枚举
:
#define LL long long
#define UN unsigned
#include<bits/stdc++.h>
using namespace std;
//--------------------//
const int N=1e5+1;
int n,V;
int v[N],w[N],c[N];
int ans,f[N];
int head,tail;
int q[N][2];
//--------------------//
int main()
{
scanf("%d%d",&n,&V);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&w[i],&v[i],&c[i]);
for(int i=1;i<=n;i++)
for(int r=0;r<v[i];r++)
{
head=tail=1;
q[1][0]=r,q[1][1]=f[r];
for(int tem,t,j=r+v[i];j<=V;j+=v[i])
{
tem=f[j]-j/v[i]*w[i],t=j/v[i];
while(head<=tail&&q[head][0]<j-c[i]*v[i])
head++;
f[j]=max(f[j],q[head][1]+t*w[i]);
while(head<=tail&&q[tail][1]<tem)
tail--;
q[++tail][0]=j,q[tail][1]=tem;
}
}
for(int i=1;i<=V;i++)
ans=max(ans,f[i]);
printf("%d",ans);
return 0;
}
目标点 |
目标点 |
跳至目标点 |
当前单调队列还未加入的最近位置 |
先考虑单方向的做法,显著地,按照
我们发现当
对于每一个
至于向另一方向跳的情况,将数轴左右翻转再做一遍 DP 即可。
需要饲料总数 | 中点坐标 | 商店 |
商店 |
商店 |
走到商店 |
先按照
将其转化:
显著的单调队列。其中需要注意的是初值的设置以及转移的始末位置。
x. 前置知识 决策单调性
x.1. 简介
决策单调性是一个优秀的性质,对于具有决策单调性的动态规划可以采用很多方法进行优化。
通常地,决策单调性体现在 1D 维度上。当
x.2. 四边形不等式
四边形不等式如下,在
设
证明略,待施工。
2. 斜率优化
2.1. 简介
当一个最优化 DP 的转移方程形如:
即其中有一些只关于
先对原式进行化简。设
设
具体地,我们维护一个凸包,取一次函数与切点为决策点。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】