常用技巧:单调栈
通过单调栈,可以将一些题目从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); } }