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

Maximal submatrix

题目链接

https://acm.hdu.edu.cn/showproblem.php?pid=6957

题意

给定一个 \(n\) 行 \(m\) 列的矩阵,求每个列上不递减的最大面积子矩阵

思路

令 \(sum[i][j]\) 为第 \(i\) 行第 \(j\) 列从上往下以 \(a[i][j]\) 结尾的最长不递减序列长度,枚举每一个 \(sum[i][j]\) 作为列的最长长度, 显然行长度只能延伸到左右第一个小于 \(sum[i][j]\) 的位置之前,用单调栈维护即可。

AC_Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e3 + 50;
int mp[maxn][maxn];
int sum[maxn][maxn];
int st[maxn], Lmin[maxn], Rmin[maxn], b[maxn];
void getLmin(int a[], int n){//左边第一个小于a[i]的数
    int cnt = 0;
    st[0] = 0;
    for(int i = 1;i <= n;i++){
        while(cnt && a[i] <= a[st[cnt]]) cnt--;
        Lmin[i] = st[cnt];
        st[++cnt] = i;
    }
}
void getRmin(int a[], int n){//右边第一个小于a[i]的数
    int cnt = 0;
    st[0] = n + 1;
    for(int i = n;i >= 1;i--){
        while(cnt && a[i] <= a[st[cnt]]) cnt--;
        Rmin[i] = st[cnt];
        st[++cnt] = i;
    }
}
int main()
{
    std::ios::sync_with_stdio(false);
    int t;
    cin >> t;
    while(t--){
        int n, m;
        cin >> n >> m;
        for(int i = 0;i <= n + 1;i++)
            for(int j = 0;j <= m + 1;j ++){
                mp[i][j] = sum[i][j] = 0;
            }
        for(int i = 1;i <= n;i++){
            for(int j = 1;j <= m;j++){
                cin >> mp[i][j];
            }
        }

        for(int i = 1;i <= n;i++){
            for(int j = 1;j <= m;j++){
                if(mp[i][j] >= mp[i - 1][j]) sum[i][j] = sum[i - 1][j] + 1;
                else sum[i][j] = 1;
            }
        }
        int ans = 0;
        for(int i = 1;i <= n;i++){
            for(int j = 1;j <= m;j++){
                b[j] = sum[i][j];
            }
            getLmin(b, m);
            getRmin(b, m);
            for(int j = 1;j <= m;j++){
                ans = max(ans, sum[i][j] * ( (Rmin[j] - 1) - (Lmin[j] + 1) + 1));
            }
        }
        cout << ans << endl;
    }
    return 0;
}
上一篇:PAT乙级 1008 数组元素循环右移问题 (20 分)


下一篇:PAT乙级1008