https://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1008&cid=984
题意:
从n行m列矩阵中,找出最大的满足每列不降的子矩阵
题解:
如果下一列比上一列的数大,标记T,否则标记F
问题转化为在n-1行m列矩阵中,找最大的T子矩阵
可以用悬线法,也可以单调栈
单调栈法:
枚举每一行作为子矩阵的下边界,用一个数组记录到当前行时,每一列向上连续的T数量
即遇到T加1,遇到F清零
然后用2次单调栈分别计算以每一列为T矩阵高度,向左向右能延长的宽度
因为假设若这一列往上有连续x个T,那么他只能延伸到至少有x个T的列
这个可以维护单调递增的栈求
#include<bits/stdc++.h> using namespace std; #define N 2001 int m; int a[N][N]; char b[N][N]; int c1[N],c2[N]; int q[N],t[N]; int l[N],r[N],tmp[N]; void sol(int *c,int *p) { // for(int i=1;i<=m;++i) printf("%d ",c[i]); // printf(" "); int top=0,last=0; for(int i=1;i<=m;++i) { if(!c[i]) { top=0; last=i; continue; } while(top && c[i]<=q[top]) --top; if(top) p[i]=t[top]+1; else p[i]=last+1; q[++top]=c[i]; t[top]=i; } } int main() { int T,n,ans; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) { scanf("%d",&a[i][j]); if(a[i][j]>=a[i-1][j]) b[i-1][j]='T'; else b[i-1][j]='F'; } for(int i=1;i<=m;++i) c1[i]=c2[i]=0; ans=m; for(int i=1;i<n;++i) { for(int j=1;j<=m;++j) if(b[i][j]=='T') { c1[j]++; c2[m-j+1]++; } else { c1[j]=0; c2[m-j+1]=0; } sol(c1,l); sol(c2,r); for(int j=1;j<=m;++j) tmp[j]=r[j]; for(int j=1;j<=m;++j) r[j]=m-tmp[m-j+1]+1; for(int j=1;j<=m;++j) if(c1[j]) ans=max(ans,(c1[j]+1)*(r[j]-l[j]+1)); } printf("%d ",ans); } }
悬线法: