zoukankan      html  css  js  c++  java
  • 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("
    ");
        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);
        }
    }
    View Code

    悬线法:

    https://www.cnblogs.com/TheRoadToTheGold/p/6217439.html

    作者:xxy
    本文版权归作者和博客园共有,转载请用链接,请勿原文转载,Thanks♪(・ω・)ノ。
  • 相关阅读:
    JS单例对象与构造函数对象的区别
    SVG系列
    Js极客之路
    Js极客之路
    iOS微信登录
    iOS HSV
    cocoa pods
    php中请求数据中文乱码
    付费中数字计算
    时间戳对应关系
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/15070303.html
Copyright © 2011-2022 走看看