单调队列优化 DP
0. 定位
单调队列优化 DP,解决的是这样一类问题:
状态转移的「决策集合」是一个随主状态单调滑动的窗口 ,且决策的优劣可以提前与主状态 i 解耦 。满足这两点时,原本 O(nm) 的枚举被改为 O(n)。
1. 朴素形态与优化动机
几乎所有这类 DP 都长这样:
dp[i] = opt_{j ∈ [L(i), R(i)]} ( dp[j] + w(j, i) )
L(i), R(i)是决策j的合法区间;- 若区间长度有界(如
R(i) − L(i) ≤ m),朴素枚举为O(nm)。
优化的目标只有一个:在每个 i 用 O(1) 取出窗口内最优的 j。
2. 单调队列的本质原理
2.1 它是什么
一个队首到队尾保持单调性的双端队列:
- 求区间最小 → 维护递增队列(队首最小);
- 求区间最大 → 维护递减队列(队首最大)。
它能以 O(1) 均摊的代价,维护一个滑动窗口的最值。
2.2 它为什么能优化 DP
关键不在「队列」本身,而在决策的支配关系:
- 处理到
i时,把候选决策j依次加入队列; - 若新决策
j₂比旧决策j₁(j₁ < j₂)更优 ,且j₂比j₁更晚离开窗口 (窗口右移,后进入者更晚被淘汰),那么j₁在j₂存活期间永远不可能再成为最优 → 永久淘汰j₁; - 于是队列里始终只保留「仍可能最优」的候选,且按优劣单调排列,队首即当前窗口最优。
注:这就是「单调」的真正含义:维护的不是值的大小,而是候选决策的优劣序。只要「更优且更晚淘汰 → 永久支配」成立,结构就成立。
2.3 可分离性(拆项)
要让「j 的优劣」独立于 i,必须能把代价写成:
dp[j] + w(j, i) = f(j) + g(i)
f(j) 只与决策 j 有关,g(i) 只与主状态 i 有关。这样窗口内比较的始终是 f(j),与 i 无关,才塞得进单调队列。
3. 适用条件(判定法则)
必须同时满足以下三点才可用:
- 决策区间单调滑动 :
L(i), R(i)随i非降(典型如定长窗口[i − m, i − 1])。 - 目标可分离 :
w(j, i)能拆成f(j) + g(i)(或更一般、对j单调可比的形式)。 - 可比较性 :比较两个决策
j₁ < j₂的优劣时,结论不依赖i(即f(j₂) ≤ f(j₁)一旦成立便恒成立)。
不满足反例 :w(j, i) = j · i(交叉项,优劣随 i 翻转)→ 单调队列无能为力,需斜率优化或分治优化。
4. 通用形态与模板
形式化结论:
若 dp[i] = g(i) + opt{ f(j) }, j ∈ 滑动窗口
则 用单调队列在窗口内维护 f(j),队首即 opt。
最小模板(求 min,递增队列):
dq = 双端队列,存 j 的下标
for i = 1 .. n:
while dq 队首越出窗口: pop_front()
dp[i] = g(i) + f(dq.front())
while dq 非空 且 f(i) <= f(dq.back()): pop_back() # 支配淘汰
dq.push_back(i)
(求 max 改递减队列、比较符号反转即可。)
5. 经典模型精析
模型 A | 连续区间「至少选 1」
- 代表:烽火传递、绿色通道。
- 建模 :
dp[i] = cost[i] + min{ dp[j] },j ∈ [i − m, i − 1](第i个必选,上一个被选者在窗口内)。 - 优化关键 :窗口内只比
dp[j],与i无关 → 递增队列维护dp[j],O(n)。答案为最后m个dp的最小值。
模型 B | 连续区间「至多选 k」
- 代表:修剪草坪(USACO)。
- 建模 :前缀和
s,dp[i] = max( dp[i−1], s[i] + max{ dp[j] − s[j] } ),j ∈ [i − k, i − 1](选i且被选段长 ≤ k)。 - 优化关键 :把前缀和
s[i]拆出(只与i有关),窗口内只比dp[j] − s[j]→ 递减队列,O(n)。与 A 对偶。
模型 C | 二维滑窗最值
- 代表:理想的正方形。
- 建模:正方形最值 = 行方向滑窗后再列方向滑窗。
- 优化关键 :一维滑窗做两次(先每行、再每列),将
n×n区域最值降到O(ab)。本质是「单调队列在二维的两次投影」。
模型 D | 多重背包
- 代表:多重背包的单调队列优化。
- 建模 :
dp[r + t·w] = max_m ( dp[r + m·w] − m·v ) + t·v,按j mod w分组。 - 优化关键 :余数固定后,体积按步长
w等距,窗口宽度c + 1滑动;维护dp[r + m·w] − m·v的递减队列,把O(V·c)降到O(V)。
6. 本质再认识
- 它 ≠ 单调栈:栈处理「固定方向第一个极值」(端点不回退);队列处理「两端都会动的窗口」。DP 优化里九成是队列。
- 它 ≠ 斜率优化 :斜率优化处理
a(i)·b(j) + c(j)这类交叉线性项(需凸包);单调队列处理「可加性分离」项。两者都依赖「决策优劣可提前排序」。 - 边界意识 :答案取段、窗口端点 ------错一处即 WA。编码前务必先写清「
j的合法范围」。
7. 一句话总结
单调队列优化 DP = 决策窗口单调滑动 × 代价可加性分离。
把只与
j有关的f(j)塞进双端队列,用支配关系淘汰永不为最优的旧决策,每个i在O(1)取最优。
部分内容由 AI 润色