2021“MINIEYE杯”中国大学生算法设计超级联赛(1)
Maximal submatrix
方法1悬线:由于题目是每一列一段区间,不好看,先把矩阵倒置变换
在进行 行间变换时,条件是两者同时足a[i] [j] <= a[i] [j+1] && a[i-1] [j] <= a[i-1] [j+1]
#include <bits/stdc++.h>
using namespace std;
const int N=2003;
int n,m,a[N][N],h[N][N],ans2,ans1;
int l[N][N],r[N][N];
signed main()
{
int t,n,m;
cin>>t;
while(t--)
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
int aa;
scanf("%d",&aa);
a[j][i] = aa;
l[j][i] = r[j][i] = i;
h[j][i] = 1;
}
}
for(int i=1;i<=m;i++)
{
for(int j=2;j<=n;j++)
{
if(a[i][j] >= a[i][j-1])
{
l[i][j] = l[i][j-1];
}
}
}
for(int i=1;i<=m;i++)
{
for(int j=n-1;j>=1;j--)
{
if(a[i][j] <= a[i][j+1])
{
r[i][j] = r[i][j+1];
}
}
}
int ans = m;
for(int i=2;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
if(a[i][j] <= a[i][j+1] && a[i-1][j] <= a[i-1][j+1])
{
l[i][j] = max(l[i][j], l[i-1][j]);
r[i][j] = min(r[i][j], r[i-1][j]);
h[i][j]=h[i-1][j]+1;
}
int aa= (r[i][j]-l[i][j]+1)*h[i][j];
ans = max(ans, aa);
}
}
cout<<ans<<endl;
}
return 0;
}
方法二单调栈:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2005;
int a[N][N], h[N], s[N], dp[N][N], w[N];
signed main()
{
ios_base::sync_with_stdio(false);
int t, n, m;
cin>>t;
while(t--)
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
}
}
int ans=m;
memset(dp, 0, sizeof(dp));
memset(h, 0, sizeof(h));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i][j] >= a[i-1][j]) h[j]++;
else h[j] = 1;
}
int p=0;
for(int j=1;j<=m+1;j++)
{
if(h[j] >= s[p]) // 单调栈,保证列选取不下降
{
s[++p] = h[j];
w[p] = 1;
}
else
{
int ww=0;
while(s[p] > h[j])
{
ww += w[p];
dp[i][j-1] = max(dp[i][j-1], ww*s[p]);
p--;
// 出栈,依次向前添加列,ww+ ,求出以(i,j-1)为右下角的最大矩形面积
}
s[++p] = h[j]; w[p] = ww+1;
// 第j列入栈,第j列的宽度 w[p] 除去本身的1,还有在之前出栈的大于h[j]的
}
ans = max(ans, dp[i][j-1]);
}
}
cout<<ans<<endl;
}
return 0;
}