1. 程式人生 > >筆記——單調佇列&&單調棧優化DP

筆記——單調佇列&&單調棧優化DP

眾所周知

動態規劃 的 題

往往 推了a long time
但是o(n^3)
於是就自閉了

所以我們有了

單調佇列和棧

這種東西

神奇的單調佇列

有這麼一道題

樸素 o(n^2)

亂搞 o(nlog n)(線段樹、RMQ)

然後。。。
單調佇列
o(n)
對,你沒有看錯,就是一遍 其實是o(2n)?!
單調佇列
用一個東西(棧、佇列、陣列。。。隨君所好)
然後,
解釋都在註釋裡

#include <cstdio>
using namespace std;
const int MAXN = 1000001;
int num[MAXN],
q[MAXN],it[MAXN],q1[MAXN],it1[MAXN]; /*要求最大和最小,q-min,q1-max it&&it1記錄q和q1中元素原來所在位置 num記錄讀入的值 */ int ALL,Begin,End,Begin1,End1,pr[MAXN]; /* ALL充當二次輸出的Index,pr則記錄二次輸出的值 Begin,End記錄q的隊首&&隊尾 Begin1,End1記錄q1的隊首&&隊尾 */ int main() { int n,k,i; scanf("%d%d",&n,&k); for
(i = 1;i <= n;i++) scanf("%d",&num[i]); //讀入 for(i = 1;i <= n;i++) { if(Begin == 0) { ++Begin,++End; q[Begin] = num[i]; it[Begin] = i; ++Begin1,++End1; q1[Begin1] = num[i]; it1[Begin1] =
i; //其實上面這一步無必要 } else { while(q[End] >= num[i]&&End >= Begin) --End; /*當q的隊尾元素大於此時要處理的num[i] 因為q-min 所以此時q的隊尾元素以後絕不會再用到 */ End++; //加之前的End是不滿足q[End] >= num[i]&&End >= Begin q[End] = num[i]; it[End] = i; //記錄對應的值 while(q1[End1] <= num[i]&&End1 >= Begin1) --End1; End1++; q1[End1] = num[i]; it1[End1] = i; //同求MIN,符號 反一下 } //這樣處理後q的隊首一定min,q1一定max if(i >= k) { //符合題意,可以輸出了 while(it[Begin] < i - k + 1) Begin++; //如果q此時隊頭不在範圍中 while(it1[Begin1] < i - k + 1) Begin1++; //同上 ALL++; //記錄二次輸出的值 pr[ALL] = q1[Begin1]; printf("%d ",q[Begin]); } } putchar('\n'); //putchar常數優化,然而並沒有什麼用 for(i = 1;i <= ALL;i++) printf("%d ",pr[i]); }

Max Sum of Max-K-sub-sequence

單調佇列與dp的關係

一道例題
瑰麗華爾茲
在一個狀態轉移方程中

dp[][][][]..[]= ....

在一定條件下可以將最後一維壓縮成單調佇列