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;
}