單調棧總結

單調棧總結


前言

刷了幾道題沒發現啥特別的用處,基本都是個板子;c++

單調棧能夠O(n)的求一個序列中每一個數左(右)邊第一個大於(小於)他的位置;spa


例題

美麗的序列code

爲了研究這個序列的美麗程度,GD定義了一個序列的「美麗度」和「美麗係數」:對於這個序列的任意一個區間[l,r],這個區間的「美麗度」就是這個區間的長度與這個區間的最小值的乘積,而整個序列的「美麗係數」就是它的全部區間的「美麗度」的最大值。如今GD想要你幫忙計算這個序列的「美麗係數」。blog

 

其實就是個板子,考慮每一個數字可以控制的區間就是右邊第一個小於他的數字到左邊第一個小於他的數字之間,單調棧秒隊列

 

海報PLAget

每一個建築物有高和寬,用矩形海報覆蓋全部建築物,求最少須要幾張海報;數學

考慮到一張海報要貼一定是擴展到左右最遠處最優,而不一樣的高度差意味着須要不一樣的海報;it

換句話說,相同高度的兩個建築能夠共用一張海報完成,因此初始ans=n,在單調棧過程當中遇到相同高度ans-1便可class

 

音樂會的等待擴展

N我的正在排隊進入一個音樂會。人們等得很無聊,因而他們開始轉來轉去,想在隊伍裏尋找本身的熟人。隊列中任意兩我的A和B,若是他們是相鄰或他們之間沒有人比A或B高,那麼他們是能夠互相看得見的。

寫一個程序計算出有多少對人能夠互相看見。

搞一下單調棧,棧內每有一個小於本身的元素就++ans,高度相同的不該該彈棧,就用二元組記錄當前高度有多少人

貼代碼

#include<bits/stdc++.h>
using namespace std; #define int long long inline int read() { int x=0,f=1; char ch; for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); if(ch=='-') f=0,ch=getchar(); while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?x:-x; } typedef pair<int,int> p; int n,ans,top; p st[1000010]; signed main() { n=read(); for(int x,i=1;i<=n;++i) { x=read(); p now(x,1); for(;top&&x>=st[top].first;--top) { ans+=st[top].second; if(x==st[top].first) now.second+=st[top].second; } ans+=(top!=0); st[++top]=now; } printf("%lld\n",ans); return 0; }

 

長方形

給定n*m的01矩陣,求所有由1組成的矩陣的個數;

 

對於每一個點(i,j)預處理出一個h[ i ][ j ]表示從(i,j)向上最多能延伸遠

找出l[ i ][ j ]和r[ i ][ j ] 表示左邊第一個h[ i ][ j ]第一個不大於當前h[ i ][ j ]的位置和右邊第一個小於當前h[ i ][ j ]的位置

這樣能夠作到不重不漏

ans+=(j - l[ i ][ j ])*(r[ i ][ j ] - j)* h[ i ][ j ];

式子解釋:左邊在 j 到 l[ i ][ j ]之間任選位置,右邊在r到r[ i ][ j ]之間任選位置,高度在1到h[ i ][ j ]之間任選位置,組合數學QAQ

#include<bits/stdc++.h>
using namespace std; #define int long long inline int read() { int x=0,f=1; char ch; for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); if(ch=='-') ch=getchar(),f=0; while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?x:-x; } int n,m,res; int mp[1010][1010]; int h[1010][1010]; int l[1010],r[1010]; int st[1010],top; char ch; inline void work(int x) { top=0; for(int i=1;i<=m;++i) { while(top&&h[x][st[top]]>=h[x][i]) { r[st[top--]]=i; } st[++top]=i; } while(top) { r[st[top--]]=m+1; } for(int i=m;i>=1;--i) { while(top&&h[x][st[top]]>h[x][i]) { l[st[top--]]=i; } st[++top]=i; } while(top) { l[st[top--]]=0; } } signed main() { n=read(),m=read(); for(int i=1;i<=n;++i) { for(int j=1;j<=m;++j) { for(ch=getchar();(ch!='.'&&ch!='*');ch=getchar()); if(ch=='.') mp[i][j]=1,h[i][j]=h[i-1][j]+1; } } for(int i=1;i<=n;++i) { work(i); for(int j=1;j<=m;++j) { res+=(j-l[j])*(r[j]-j)*h[i][j]; } } printf("%lld\n",res); return 0; }

 

玉蟾宮

給定01矩陣,求最大的所有由1構成的矩陣;

與上一題思路相似,這一題求出左右第一個小於的位置而後直接算最大

相關文章
相關標籤/搜索