学习笔记 【单调队列优化DP】

单调队列优化DP

一般的DP时间复杂度较高,我们需要一些手段优化来满足优秀的复杂度。我DP都不会是不是可以不学了

单调队列性质:

单调队列内部元素具有单调性。一般包括以下两种操作:

  1. 插入:如果插入元素破坏单调性,就删除队尾元素,直到满足单调性。再将其插入到队列。
  2. 获取最值:取队首元素(注!)

一般地,利用单调队列优化时,每个元素储存两个值:

  1. 它在原序列的下标。
  2. 它在动态规划的状态值。
    要满足这两个性质同时单调。

将扫描之前的状态最大值来更新现在的状态的时间由 \(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\) 的范围内了,不会再更新新状态了,就要删掉。

来整理操作:

  1. 弹不在范围内的队首元素。
  2. 用新元素弹出破坏单调性的元素。
  3. 插入新元素。
  4. 取队首最优值更新。

复杂度 \(O(n)\)
在一些转移方程形如

\[f_i=\max\{f_j+cal(i)\} \]

\(j<i\)\(cal(i)\)\(j\) 无关,此时可以将 \(f_j\) 扔进单调队列。

习题:

[SCOI2010] 股票交易

posted @ 2021-07-29 19:57  Mr_think  阅读(220)  评论(0)    收藏  举报