学习笔记 【单调队列优化DP】
单调队列优化DP
一般的DP时间复杂度较高,我们需要一些手段优化来满足优秀的复杂度。我DP都不会是不是可以不学了
单调队列性质:
单调队列内部元素具有单调性。一般包括以下两种操作:
- 插入:如果插入元素破坏单调性,就删除队尾元素,直到满足单调性。再将其插入到队列。
- 获取最值:取队首元素(注!)
一般地,利用单调队列优化时,每个元素储存两个值:
- 它在原序列的下标。
- 它在动态规划的状态值。
要满足这两个性质同时单调。
将扫描之前的状态最大值来更新现在的状态的时间由 \(O(n)\) 优化成了 \(O(1)\) (均摊)。
什么时候用:
来看一道例题:
给你一个长度为 \(n\) 的序列,要求找到一段连续的长度不超过 \(m\) 的子序列,使得序列的和最大。\(n,m\leq200000\)。
很显然的 \(O(nm)\) 的暴力做法。
考虑一个优化。推一下柿子:
\[f_i=\max{\{\sum ^i _{j=i-k+1}a_i|k=1...m\}}
\]
令
\[s_i= \sum ^i _{j=1} a_j
\]
\[f_i=\max\{s_i-s_{i-k}\}
\]
\[=s_i-\min\{s_{i-k}\}
\]
可以看出 \(s_i\) 是个定值,所以每次取出 \(s_{i-k}\) 的最小值即可推出最大值。这个可以用小根堆维护。 \(O(n \log_2 n)\)。
我们考虑用单调队列优化。在添加\(s_{i-1}\)时设队尾元素为\(s_k\),由于 \(k<i-1\) ,\(k\) 必然先出队。若\(s_{i-1}<s_k\) 那么\(s_k\) 这个决策就永远不会用到了。设当前队头元素 \(s_j\) , 若\(j\) 已经不在长度 \(m\) 的范围内了,不会再更新新状态了,就要删掉。
来整理操作:
- 弹不在范围内的队首元素。
- 用新元素弹出破坏单调性的元素。
- 插入新元素。
- 取队首最优值更新。
复杂度 \(O(n)\) 。
在一些转移方程形如
\[f_i=\max\{f_j+cal(i)\}
\]
中 \(j<i\) 且 \(cal(i)\) 与 \(j\) 无关,此时可以将 \(f_j\) 扔进单调队列。

浙公网安备 33010602011771号