剛學單調佇列時,在網上各大部落格找文章學,說實話,寫得很雜,表示自己懵逼了些許,最後硬是啃出來了,所以我決定要寫一篇能讓大部分人都看懂的部落格來。
說單調佇列,那我們就先說說這個單調佇列是個什麼物種。單調佇列從字面上看,無非就是有某種單調性的佇列,沒錯,這就是所謂的單調佇列。 單調佇列它分兩種,一種是單調遞增的,另外一種是單調遞減的。
用單調佇列來解決問題,一般都是需要得到當前的某個範圍內的最小值或最大值。
舉個例子:有 7 6 8 12 9 10 3 七個數字,現在讓你找出範圍( i-4,i ) 的最小值。
那我們就可以這樣模擬一遍。
先初始化 (表示i=0時的值)
i=1 -> (表示i=1,時,在其範圍內最小的值為0)-> 7進隊 ;
i=2->(表示i=2,時,在其範圍內最小的值為7)-> 6比7小,7出,6進 ;
i=3-> (表示i=3,時,在其範圍內最小的值為6)->8比6大,8進 ;
i=4->(表示i=4,時,在其範圍內最小的值為6)-> 12比8大,12進 ;
i=5-> (表示i=4,時,在其範圍內最小的值為6)-> 9比12小,12out,9比8大,9進 ;
i=6-> 但是 單調佇列中元素6的下標是2,不在(2, 6],中,故6 out,這就是單調佇列的精髓了。故單調隊列為
(表示i=5,時,在其範圍內最小的值為8)->10比9大,10進 最終 單調隊列為 ;
i=7->(表示i=6,時,在其範圍內最小的值為8)-> 3比單調隊列為 的任意值都小,故全out,最終集合為 ;
相信大家看完這個例子了解得有些吧,再次重申一遍,單調佇列的核心(我認為的哈):得到當前的某個範圍內的最小值或最大值。要不是這樣的話,那還有必要這麼麻煩找嗎,直接找前面最小的就好了,可事實不是這樣,題目是有限制的,規定在某個範圍內找。
那我們就來看到例題,加深理解:
description
乙個長度為n的整數序列,從中找出一段不超過m的連續子串行,使得整個序列的和最大。
例如: 1, -3, 5, 1, -2, 3
當m=4時,sum = 5+1-2+3 = 7
當m=2或m=3時,sum = 5+1 = 6
input
多測試用例,每個測試用例:
第一行是兩個正數n, m ( n, m ≤ 300000 )
第二行是n個整數
output
每個測試用例輸出一行:乙個正整數,表示這n個數的最大子序和長度
sample input
6 41 -3 5 1 -2 3
sample output
這題可以用dp來解,在這我們就用單調佇列來解。
我們先把序列的前i項和加起來並存到乙個陣列sum[ ]上,那麼任意連續的子串行和就為sum [ i ] - sum[ j ] (i>j && j>i-m)。
那麼我們就可以跟上述例子一樣,一直更新就好了,每次找出在(i-m,i)範圍內的最小sum[j]值。
**一:
#include
#include
///單調佇列,
#include
#include
using
namespace std;
typedef
long
long ll;
const
int maxn=
300010
;ll sum[maxn]
;list <
int> que;
intmain()
///初始化
ll maxs=sum[1]
; que.
push_front(1
);for(
int i=
2;i<=n;i++
)printf
("%lld\n"
,maxs);}
return8;
}
**二:
#include
///單調遞增序列(但保證最可能小)
#include
#include
using
namespace std;
typedef
long
long ll;
const ll maxn=
300010
;ll sum[maxn]
;ll index1[maxn]
;///儲存下標
intmain()
///初始化
int left=
1,right=1;
index1[1]
=1; ll tmax=sum[1]
;for
(int i=
2;i<=n;i++
)printf
("%lld\n"
,tmax);}
return0;
}
剛學單調佇列時,在網上各大部落格找文章學,說實話,寫得很雜,表示自己懵逼了些許,最後硬是啃出來了,所以我決定要寫一篇能讓大部分人都看懂的部落格來。
說單調佇列,那我們就先說說這個單調佇列是個什麼物種。單調佇列從字面上看,無非就是有某種單調性的佇列,沒錯,這就是所謂的單調佇列。 單調佇列它分兩種,一種是單調遞增的,另外一種是單調遞減的。
用單調佇列來解決問題,一般都是需要得到當前的某個範圍內的最小值或最大值。
舉個例子:有 7 6 8 12 9 10 3 七個數字,現在讓你找出範圍( i-4,i ) 的最小值。
那我們就可以這樣模擬一遍。
先初始化 (表示i=0時的值)
i=1 -> (表示i=1,時,在其範圍內最小的值為0)-> 7進隊 ;
i=2->(表示i=2,時,在其範圍內最小的值為7)-> 6比7小,7出,6進 ;
i=3-> (表示i=3,時,在其範圍內最小的值為6)->8比6大,8進 ;
i=4->(表示i=4,時,在其範圍內最小的值為6)-> 12比8大,12進 ;
i=5-> (表示i=4,時,在其範圍內最小的值為6)-> 9比12小,12out,9比8大,9進 ;
i=6-> 但是 單調佇列中元素6的下標是2,不在(2, 6],中,故6 out,這就是單調佇列的精髓了。故單調隊列為
(表示i=5,時,在其範圍內最小的值為8)->10比9大,10進 最終 單調隊列為 ;
i=7->(表示i=6,時,在其範圍內最小的值為8)-> 3比單調隊列為 的任意值都小,故全out,最終集合為 ;
相信大家看完這個例子了解得有些吧,再次重申一遍,單調佇列的核心(我認為的哈):得到當前的某個範圍內的最小值或最大值。要不是這樣的話,那還有必要這麼麻煩找嗎,直接找前面最小的就好了,可事實不是這樣,題目是有限制的,規定在某個範圍內找。
那我們就來看到例題,加深理解:
description
乙個長度為n的整數序列,從中找出一段不超過m的連續子串行,使得整個序列的和最大。
例如: 1, -3, 5, 1, -2, 3
當m=4時,sum = 5+1-2+3 = 7
當m=2或m=3時,sum = 5+1 = 6
input
多測試用例,每個測試用例:
第一行是兩個正數n, m ( n, m ≤ 300000 )
第二行是n個整數
output
每個測試用例輸出一行:乙個正整數,表示這n個數的最大子序和長度
sample input
6 41 -3 5 1 -2 3
sample output
這題可以用dp來解,在這我們就用單調佇列來解。
我們先把序列的前i項和加起來並存到乙個陣列sum[ ]上,那麼任意連續的子串行和就為sum [ i ] - sum[ j ] (i>j && j>i-m)。
那麼我們就可以跟上述例子一樣,一直更新就好了,每次找出在(i-m,i)範圍內的最小sum[j]值。
**一:
單調佇列詳解
剛學單調佇列時,在網上各大部落格找文章學,說實話,寫得很雜,表示自己懵逼了些許,最後硬是啃出來了,所以我決定要寫一篇能讓大部分人都看懂的部落格來。說單調佇列,那我們就先說說這個單調佇列是個什麼物種。單調佇列從字面上看,無非就是 有某種單調性 的佇列,沒錯,這就是所謂的單調佇列。單調佇列 它分兩種,一...
單調棧 單調佇列詳解
首先看乙個問題。給定乙個數列,從左至右輸出每個長度為 k 的數列段內的最小數和最大數 第一行輸出每個區間最小值,第二行輸出最大值 數列長度 n leq 10 6 k leq n 解法 很直觀的一種解法,那就是從數列的開頭,找到這最開始的k個數的最大值,然後後移乙個單元,繼續找到k個數中的最大值。這種...
dp單調佇列(詳解)
我們從最簡單的問題開始 給定乙個長度為n的整數數列a i i 0,1,n 1和窗長度k.要求 f i max,i 0,1,n 1 問題的另一種描述就是用乙個長度為k的窗在整數數列上移動,求窗裡面所包含的數的最大值。解法一 很直觀的一種解法,那就是從數列的開頭,將窗放上去,然後找到這最開始的k個數的最...