【單調棧】
基本過程:
讓我們來模擬乙個遞增的單調棧的實現過程,以序列為例。
主要步驟如下:若棧為空或者棧頂元素小於當前元素則壓入,否則彈出棧內比當前元素大的所有元素。
第一步:棧為空,壓入7。此時棧內:7 。可以在紙上模擬一下這個過程。在這個過程中我們可以跑出以每個元素作為最小值的最左端點下標。第二步:7比2大,彈出7,壓入2。此時棧內:2 。
第三步:2比5小,壓入5。此時棧內:2 5 。
第四步:5比3大,彈出5,2比3小,壓入3。此時棧內:2 3 。
第五步:3比11小,壓入11 。此時棧內:2 3 11 。
第六步:11比9大,彈出11,3比9小,壓入9 。此時棧內:2 3 9 。
【實現**】
#include using namespace std;
int main()
; int l[10];
stack stk;
for(int i=1;i<=6;i++)
for(int i=1;i<=6;i++)
printf(i<6?"%d ":"%d\n",l[i]);
}
跑出來的結果是1,1,3,3,5,5
同理,我們可以跑出每個元素作為最小值的最右端點的下標,只要從右往左跑就可以了。還有用遞減的單調棧跑出每個元素作為最大值的區間的下標。可以自己嘗試寫一下。時間複雜度為o(n).
【單調棧基礎應用】
1.給定一組數,跑出每個數和他右邊第乙個比他大(小)的數之間有多少個數。
2.給定一串行,尋找某一子串行使得子串行中的最小值乘以子串行的長度最長。
3.給定一串行,尋找某一子串行使得子串行中的最小值乘以子串行所有元素和最大。
【例題講解】
ex1:poj3250
bad hair day
【題解】
題意:每頭牛面朝右邊,只能看到比他矮的牛,詢問所有的牛能看到的牛的數目的期望。
思路:從前往後跑,每次彈出小於等於當前身高的元素,因為如果不高於當前身高就沒辦法越過這個位置看到後面的牛。然後每次加上當前棧內元素個數,即能看到這個位置的前面的牛的數目即可。
【**】
#include #include using namespace std;
#define ll long long
int main()
while(!stk.empty()) stk.pop();
for(int i=n;i>0;i--)
ll ans=0;
for(int i=1;i<=n;i++)
ans=max(ans,a[i]*(r[i]-l[i]+1));
printf("%lld\n",ans);
}}
ex3:poj2796
feel good
【題解】
題意:給定乙個長度為n的序列,輸出區間最小值乘區間和最大的乙個區間的值和左右端點。
思路:跑出以每個位置為最小值的左右區間,用字首和維護區間和,更新最大答案即可。
【**】
#include #include using namespace std;
#define ll long long
const int maxn=1e5+10;
ll a[maxn],sum[maxn];
int l[maxn],r[maxn];
int main()
while(!stk.empty()) stk.pop();
for(int i=n;i>=1;i--)
ll ans=-1,ret,index;
for(int i=1;i<=n;i++)
}printf("%lld\n%d %d\n",ans,l[index],r[index]);
}return 0;
}
單調佇列和單調棧例題
1 單調佇列 給出乙個長度為n的序列和區間長度k 從左向右對每乙個長度為k的區間詢問最大值和最小值。思路 對於最小值,考慮維護乙個遞增的雙端佇列,每次入隊時將隊尾比當前入隊元素的全部刪除,每次取隊首並且判斷是否在當前區間內即可 author hairu,wu from ahut include in...
單調棧與單調佇列簡單例題
poj3250 題意 有n只奶牛排成一列向右看,每頭奶牛只能看到比自己矮的奶牛,即會被高的奶牛擋住後面,問共有多少只奶牛能被看到 思路 考慮每頭奶牛能被前面牛看到的次數,也就是從他左邊開始單調遞減的序列的長度,用單調棧維護即可 include includeusing namespace std c...
單調棧 模板及相應例題
單調棧可以存一段元素每個之前第乙個比它小的元素的下標,沒有的置為 1。以下是單調遞增棧的模板,即棧中的元素為單調遞增的。在入棧之前記錄當前元素左邊第乙個比他小的元素的下標 for int i 1 i n i 以下是單調遞減棧的模板,即棧中的元素為單調遞減的,若當前元素比棧頂元素大,所以棧頂元素為第乙...