學習筆記 【單調佇列優化DP】
阿新 • • 發佈:2021-07-29
單調佇列優化DP
一般的DP時間複雜度較高,我們需要一些手段優化來滿足優秀的複雜度。我DP都不會是不是可以不學了
單調佇列性質:
單調佇列內部元素具有單調性。一般包括以下兩種操作:
- 插入:如果插入元素破壞單調性,就刪除隊尾元素,直到滿足單調性。再將其插入到佇列。
- 獲取最值:取隊首元素(注!)
一般地,利用單調佇列優化時,每個元素儲存兩個值:
- 它在原序列的下標。
- 它在動態規劃的狀態值。
要滿足這兩個性質同時單調。
將掃描之前的狀態最大值來更新現在的狀態的時間由 \(O(n)\) 優化成了 \(O(1)\) (均攤)。
什麼時候用:
來看一道例題:
給你一個長度為 \(n\) 的序列,要求找到一段連續的長度不超過 \(m\)
很顯然的 \(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}\)
來整理操作:
- 彈不在範圍內的隊首元素。
- 用新元素彈出破壞單調性的元素。
- 插入新元素。
- 取隊首最優值更新。
複雜度 \(O(n)\) 。
在一些轉移方程形如
中 \(j<i\) 且 \(cal(i)\) 與 \(j\) 無關,此時可以將 \(f_j\)