常用技巧:單調棧
阿新 • • 發佈:2020-10-09
通過單調棧,可以將一些題目從O(n2)降到O(n),不需要列舉,掃描一遍將之前的結果存到棧中,處理當前位置時從棧中獲取之前的資訊,並將當前位置存入棧中。典型模型是求最大矩陣:POJ2559
#include<stdio.h> #include<algorithm> using namespace std; typedef long long ll; int n; int h[100005],l[100005],r[100005],st[100005]; int main(){ while(scanf("%d",&n)!=EOF){ if(n==0) break;for(int i=1;i<=n;i++) scanf("%d",&h[i]); int t=0; for(int i=1;i<=n;i++){ while(t>0&&h[i]<=h[st[t-1]]) t--; if(t==0) l[i]=1; else l[i]=st[t-1]+1; st[t++]=i; } t=0; for(int i=n;i>=1;i--){while(t>0&&h[i]<=h[st[t-1]]) t--; if(t==0) r[i]=n+1; else r[i]=st[t-1]; st[t++]=i; } ll ans=0; for(int i=1;i<=n;i++){ ans=max(ans,(ll)h[i]*(r[i]-l[i])); } printf("%lld\n",ans); } }
POJ3494,求最大全1子矩陣。可以分行處理,根據當前位置上的情況,決定在當前位置的高度。h[j]=map[i][j]==0?0:h[j-1]+1,那麼就成為一個在當前行上求最大矩形面積的問題。類似壓行的思想還有求最大子矩陣和的問題,把每列上的數累積求和,在每行上解決最大子段和問題即可。
#include<stdio.h> #include<algorithm> using namespace std; int m,n,num[2005][2005],h[2005],l[2005],r[2005],st[2005]; int main(){ while(scanf("%d%d",&m,&n)!=EOF){ for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ scanf("%d",&num[i][j]); } } int ans=0; for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ h[j]=num[i][j]==0?0:h[j]+1; } int t=0; for(int j=1;j<=n;j++){ while(t>0&&h[j]<=h[st[t-1]]) t--; if(t==0) l[j]=1; else l[j]=st[t-1]+1; st[t++]=j; } t=0; for(int j=n;j>=1;j--){ while(t>0&&h[j]<=h[st[t-1]]) t--; if(t==0) r[j]=n+1; else r[j]=st[t-1]; st[t++]=j; } for(int j=1;j<=n;j++){ ans=max(ans,h[j]*(r[j]-l[j])); } } printf("%d\n",ans); } }