本题使用悬线法。
针对于每一点来说,他向上能到多长取决于上一个点的情况,如果上一个点与他相反那就h[i][j] = h[i-1][j]+1,否则的话就是 1。
那么对于每一个点左边最长是多少,右边最长是多少都能求出来。
然后我们可以看到在竖直方向会产生许多悬线,那么接下来去取这些悬线最大到左边和右边分别是多少。
最后的结果就是某个悬线可以形成的最大矩形,再根据面积公式计算即可。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 2000+10;
int n, m;
int mp[maxn][maxn];
int h[maxn][maxn], l[maxn][maxn], r[maxn][maxn];
signed main()
{
cin>>n>>m;
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]||i==1) h[i][j] = 1;
else h[i][j] = h[i-1][j] + 1;
if (mp[i][j]==mp[i][j-1]||j==1) l[i][j] = 1;
else l[i][j] = l[i][j-1] + 1;
}
// for (int i=1;i<=n;i++)
// {
// for (int j=1;j<=m;j++)
// {
// cout<<h[i][j]<<' ';
// }
// cout<<'\n';
// }
//倒着遍历取找最右边
for (int i=1;i<=n;i++)
for (int j=m;j>=1;j--)
{
if (j==m||mp[i][j]==mp[i][j+1]) r[i][j] = 1;
else r[i][j] = r[i][j+1]+1;
}
// for (int i=1;i<=n;i++)
// {
// for (int j=1;j<=m;j++)
// {
// cout<<r[i][j]<<' ';
// }
// cout<<'\n';
// }
//走一遍求每一个悬线的左右两边最大距离
for (int i=2;i<=n;i++)
for (int j=1;j<=m;j++)
{
if (h[i][j]>1)
{
l[i][j] = min(l[i][j], l[i-1][j]);
r[i][j] = min(r[i][j], r[i-1][j]);
}
}
// for (int i=1;i<=n;i++)
// {
// for (int j=1;j<=m;j++)
// {
// cout<<l[i][j]<<' ';
// }
// cout<<'\n';
// }
int square=0, rectangle=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
square = max(square, h[i][j]*(l[i][j]+r[i][j]-1));
int len = min(h[i][j], l[i][j]+r[i][j]-1);
rectangle = max(rectangle, len*len);
}
cout<<rectangle<<endl;
cout<<square;
return 0;
}

京公网安备 11010502036488号