1. 程式人生 > 其它 >學習筆記 【單調佇列優化DP】

學習筆記 【單調佇列優化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] 股票交易