「Note」DP 方向 - DP 优化
1. 单调队列优化 DP
1.1. 简介
当一个选手比你小还比你强,你就打不过他了。这是对单调队列简单形象的概括。
单调队列在转移的过程中不断排除不可能成为决策点的元素,使每次转移寻找决策点的时间复杂度降为 \(O(1)\)。一般地,可被单调队列优化的转移式可被写为如下形式:
\]
\]
其中需要满足 \(l_i\) 单调不降,\(A_i\) 是只与 \(i\) 有关的变量,\(B_j\) 是只与 \(j\) 有关的变量。
不难发现单调队列要维护的是 \(F_i+A_i\),每次 \(j1\) 入队时,若满足 \(F_{j1}+A_{j1}>F_{j0}+A_{j0}\) 则将 \(j0\) 弹出,直到不满足条件或者队列为空。
此时取队头元素,它一定满足在范围内最优,将其作为决策点即可。特殊地,有时需要特判队列为空的情况。
1.2. 常见技巧
大部分情况下,转移方程并不显著,因为在其中的贡献往往与 \(i,j\) 都有关,此时尝试将贡献转化为 \(A_j+B_i\) 的形式,然后在单调队列中维护 \(F_i+A_i\) 即可。
1.3. 例题
\(\color{limegreen}{P1776}\)(单调队列优化多重背包)
\(v_i\) | \(w_i\) | \(c_i\) | \(F_{i,j}\) |
---|---|---|---|
物品 \(i\) 的体积 | 物品 \(i\) 的价值 | 物品 \(i\) 的个数 | 前 \(i\) 个物品放入总体积为 \(j\) 的物品的最大价值 |
显著地,有以下转移方程:
\]
设 \(j'=j-k\times v_i\),在保证 \(i\) 不变的情况下,分别考虑每个 \(j'\) 对 \(j\) 的贡献,此时有 \(k=\frac{j-j'}{v_i}\)。此时 \(j,j'\) 在 \(\bmod v_i\) 的意义下同余,设 \(j=t\times v_i+r\) 其中 \(0\le r<v_i\),考虑将贡献拆分有 \(j'=j-k\times v_i,k=\left\lfloor\frac{j}{v_i}\right\rfloor-\left\lfloor\frac{j'}{v_i}\right\rfloor=t-\left\lfloor\frac{j'}{v_i}\right\rfloor\),将原方程改写:
\]
不难想到在枚举 \(r\) 的基础上,枚举 \(j\) 进行单调队列优化。
$\text{Code}$:
#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;
}
\(\color{royalblue}{P3089}\)
\(x_i\) | \(p_i\) | \(F_{i,j}\) | \(now_i\) |
---|---|---|---|
目标点 \(i\) 的坐标 | 目标点 \(i\) 的分数 | 跳至目标点 \(i\),上一个目标点是 \(j\) ,所能获得的最大分数 | 当前单调队列还未加入的最近位置 |
先考虑单方向的做法,显著地,按照 \(x_i\) 排序后有以下转移方程:
\]
我们发现当 \(i\) 固定时并不能直接用单调队列优化,因为维护的 \(\max\) 中存在两个不固定值 \(j,k\)。考虑固定 \(j\),当 \(i\) 上升时,\(k\) 的范围单调不减,此时可以用单调队列维护。
对于每一个 \(j\) 维护一个单调队列,用 \(now_j\) 记录还未进队的最近位置,每次枚举 \(i\) 时,将符合条件的 \(k\) 入队,并更新 \(now_j\)。
至于向另一方向跳的情况,将数轴左右翻转再做一遍 DP 即可。
\(\color{royalblue}{P4544}\)
\(ka\) | \(e\) | \(x_i\) | \(c_i\) | \(v_i\) | \(f_{i,j}\) |
---|---|---|---|---|---|
需要饲料总数 | 中点坐标 | 商店 \(i\) 坐标 | 商店 \(i\) 库存 | 商店 \(i\) 价格 | 走到商店 \(i\) 经过交易后得到 \(j\) 个饲料的最小消费 |
先按照 \(x_i\) 排序,显著地,转移方程:
\]
将其转化:
\]
显著的单调队列。其中需要注意的是初值的设置以及转移的始末位置。
x. 前置知识 决策单调性
x.1. 简介
决策单调性是一个优秀的性质,对于具有决策单调性的动态规划可以采用很多方法进行优化。
通常地,决策单调性体现在 1D 维度上。当 \(j<j'<i<i'\) 时,若 \(F_i\) 从 \(F_{j'}\) 转移过来,那么 \(F_i'\) 不可能从 \(F_j\) 转移过来,只可能从 \(F_j'\) 或之后的状态转移。这种性质可称之为决策单调性。
x.2. 四边形不等式
四边形不等式如下,在 \(a<b<c<d\) 的情况下 \(w(a,d)+w(b,c)>w(a,c)+w(b,d)\)。
设 \(F_i\) 由 \(F_j+w(i,j)\) 转移来,若满足四边形不等式则称其具有决策单调性。
证明略,待施工。
2. 斜率优化
2.1. 简介
当一个最优化 DP 的转移方程形如:
\]
\]
即其中有一些只关于 \(i,j\) 其中一个的项和一个关于 \(i,j\) 两个变量的项,可以考虑用斜率优化来解决。
先对原式进行化简。设 \(F_i\) 由 \(F_j\) 转移过来,有 \(F_i=F_j+A_i+B_j+a_i\times b_j\),移项得:
\]
设 \(y=F_j+B_j,x=b_j,k=a_i,b=A_i-F_i\),当 \(i\) 固定时,我们得到了一个 \(k\) 固定的一次函数,使其经过不同的 \((x,y)\)(与 \(j\) 有关),可以得到不同的截距 \(b\)(与 \(F_i\) 有关),其中取截距最大或最小,可以得到 \(F_i\) 的最大或最小值,因题而异。
具体地,我们维护一个凸包,取一次函数与切点为决策点。
2.2. 常见技巧
「Note」DP 方向 - DP 优化的更多相关文章
- LG3205/BZOJ1996 「HNOI2010」合唱队 区间DP
区间DP 区间DP: 显然是一个区间向左右拓展形成的下一个区间,具有包含关系,所以可以使用区间DP. 状态设计: 考虑和关路灯一样设计状态 因为不知道当前这个区间是从哪个区间拓展而来,即不知道这个区间 ...
- LOJ 6435 「PKUSC2018」星际穿越——DP+倍增 / 思路+主席树
题目:https://loj.ac/problem/6435 题解:https://www.cnblogs.com/HocRiser/p/9166459.html 自己要怎样才能想到怎么做呢…… dp ...
- loj#2483. 「CEOI2017」Building Bridges 斜率优化 cdq分治
loj#2483. 「CEOI2017」Building Bridges 链接 https://loj.ac/problem/2483 思路 \[f[i]=f[j]+(h[i]-h[j])^2+(su ...
- loj#2002. 「SDOI2017」序列计数(dp 矩阵乘法)
题意 题目链接 Sol 质数的限制并没有什么卵用,直接容斥一下:答案 = 忽略质数总的方案 - 没有质数的方案 那么直接dp,设\(f[i][j]\)表示到第i个位置,当前和为j的方案数 \(f[i ...
- 「洛谷5017」「NOIP2018」摆渡车【DP,经典好题】
前言 在考场被这个题搞自闭了,那个时候自己是真的太菜了.qwq 现在水平稍微高了一点,就过来切一下这一道\(DP\)经典好题. 附加一个题目链接:[洛谷] 正文 虽然题目非常的简短,但是解法有很多. ...
- LOJ3058. 「HNOI2019」白兔之舞 [DP,MTT]
LOJ 前置知识:任意长度NTT 普通NTT只能做\(2^k\)的循环卷积,尝试扩展成长度为\(n\)的循环卷积,保证模意义下\(\omega_n\)存在. 不管怎样还是要算点值.推式子: \[ \b ...
- LOJ 2304 「NOI2017」泳池——思路+DP+常系数线性齐次递推
题目:https://loj.ac/problem/2304 看了各种题解…… \( dp[i][j] \) 表示有 i 列.第 j 行及以下默认合法,第 j+1 行至少有一个非法格子的概率,满足最大 ...
- 逛公园「NOIP2017」最短路+DP
大家好我叫蒟蒻,这是我的第一篇信竞题解blog [题目描述] 策策同学特别喜欢逛公园. 公园可以看成一张 \(N\) 个点 \(M\) 条边构成的有向图,且没有自环和重边.其中 \(1\) 号点是公园 ...
- BZOJ1369/LG4395 「BOI2003」Gem 树形DP
问题描述 LG4395 BZOJ1369 题解 发现对于结点 \(x\) ,其父亲,自己,和所有的孩子权值不同,共 \(3\) 类,从贪心的角度考虑,肯定是填 \(1,2,3\) 这三种. 于是套路树 ...
- 「题解」:[组合数学][DP]:地精部落
拿到这道题秒懂题意:波动序列. 然鹅不会打.想了一节课,想打纯组合数学,结果找不到规律. 想的是先假设拍出一个序列,然后交换其中的元素求组合, 无奈没啥规律可循,显然不能一口气求出来(我说的是我没办法 ...
随机推荐
- # 如何引进高级的 IT 自动化项目:一个 3 步走计划
如果您的团队与大多数 IT 组织一样,您的团队正在执行某种形式的自动化(包括开发和运营),即使只是运行简单的脚本来完成基本任务. 事实上,开始自动化之旅的最佳地点是执行普通的.低技能的任务,例如密码重 ...
- DeepSeek过时了?全网刷屏的Manus到底是什么?这样写申请秒过审核
1.Manus是什么? Manus的官网地址:https://manus.im/ Manus是一个通用AI智能体,它连接思维与行动:它不仅思考,还能交付成果. 2. Manus能做什么? 最近几天,M ...
- 插入排序(LOW)
博客地址:https://www.cnblogs.com/zylyehuo/ # _*_coding:utf-8_*_ def insert_sort(li): for i in range(1, l ...
- 【Linux】5.1 Shell简介
Shell简介 1. Shell基础 Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁.Shell 既是一种命令语言,又是一种程序设计语言. Shell 是指一种应用程序,这 ...
- Git 覆盖刚刚 commit 的 message
场景重现 通常噼里啪啦键盘一段猛搓后(写代码啊),然后会 git add . git commit -m "modify semo" # 注意上面 semo 应该是 some,发现 ...
- Golang 301永久重定向
比如我要把www.taadis.com永久重定向到taadis.com //main.go package main import ( "log" "net/http&q ...
- el-tree 动态图标
举个栗子 https://jsfiddle.net/taadis/x9crjsum/ https://jsrun.net/MYXKp - 上面看不了的,可以看这个...
- 如何使用 OpenAI Agents SDK 构建 MCP
1.概述 OpenAI Agents SDK 现已支持 MCP(模型上下文协议),这是 AI 互操作性的重大变革.这使开发人员能够高效地将 AI 模型连接到外部工具和数据源.本篇博客,笔者将指导使用 ...
- 【Guava】集合工具类-Immutable&Lists&Maps&Sets
Immutable 如<Effective Java>Item1)所述,在设计类的时候,倾向优先使用静态工厂方法(static factory method)而非构造函数(construc ...
- 中文Markmap v2.0 现已上线,新增高效功能,老板再也留不住你下班的脚步!
介绍 Markmap.js 是一款开源项目,在 GitHub 上获得了超过 1.7 万个星的关注,它的主要功能是将 Markdown 文档可视化为思维导图. 在日常使用中,用户经常需要面对老板的&qu ...