2021“MINIEYE杯”中国大学生算法设计超级联赛(1)1008 Maximal submatrix

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("\n");
    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\n",ans);
    }
}

 

上一篇:1008: 美元和人民币


下一篇:OpenSSL密码库算法笔记——第6.3.5章 验证原理