https://www.luogu.org/problemnew/show/P1169
题意:给定 n∗m的01矩形,规模小于 2000∗2000,找出最大的满足 <01交替>的子正方形和子矩形的面积。
思路:悬线法。《训练指南》第一章也有一道悬线法的题,不过这道题要求维护的01交替较难一些。
设 l/r(i,j):高为up(i,j)的悬线,向左/右01交替能到达的最远列坐标
up(i,j):(i,j)向上01交替的最长长度
up很好维护, l/r的话,有一个很好的性质, (i,j)往上01交替的话,那么这根悬线往左移(过程中时终满足01交替),直到【单独考虑每一行的 l(i,j)的最大值那一列】,向右是同样的道理。
复杂度 O(n∗m)
我的语言表达能力太差了,还是洛谷排名第一的题解易懂https://www.luogu.org/problemnew/solution/P1169
#include<bits/stdc++.h>
using namespace std;
#define maxn 2010
int n,m,a[maxn][maxn];
int up[maxn][maxn],l[maxn][maxn],r[maxn][maxn];
int ans1,ans2;
int main()
{
// freopen("input.in","r",stdin);
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
if(j==1||a[i][j]==a[i][j-1])l[i][j]=j;
else l[i][j]=l[i][j-1];
for(int j=m;j>=1;j--)
if(j==m||a[i][j]==a[i][j+1])r[i][j]=j;
else r[i][j]=r[i][j+1];
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(i==1||a[i][j]==a[i-1][j])up[i][j]=1;
else{
up[i][j]=up[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]);
}
int width=r[i][j]-l[i][j]+1,high=up[i][j],len=min(high,width);
ans1=max(ans1,len*len);
ans2=max(ans2,width*high);
}
}
printf("%d\n%d\n",ans1,ans2);
return 0;
}