筆記——單調佇列&&單調棧優化DP
阿新 • • 發佈:2018-12-12
眾所周知
動態規劃 的 題
往往 推了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[][][][]..[]= ....
在一定條件下可以將最後一維壓縮成單調佇列