https://www.luogu.org/problemnew/show/P1169
题意:给定 n m n*m nm的01矩形,规模小于 2000 2000 2000*2000 20002000,找出最大的满足 &lt; 01 &gt; &lt;01交替&gt; <01>的子正方形和子矩形的面积。
思路:悬线法。《训练指南》第一章也有一道悬线法的题,不过这道题要求维护的01交替较难一些。
l / r ( i , j ) : u p ( i , j ) 线 , / 01 l/r(i,j):高为up(i,j)的悬线,向左/右01交替能到达的最远列坐标 l/r(i,j):up(i,j)线,/01
u p ( i , j ) : ( i , j ) 01 up(i,j):(i,j)向上01交替的最长长度 up(i,j):(i,j)01
u p up up很好维护, l / r l/r l/r的话,有一个很好的性质, ( i j ) (i,j) (ij)往上01交替的话,那么这根悬线往左移(过程中时终满足01交替),直到【单独考虑每一行的 l ( i , j ) l(i,j) l(i,j)的最大值那一列】,向右是同样的道理。
复杂度 O ( n m ) O(n*m) O(nm)
我的语言表达能力太差了,还是洛谷排名第一的题解易懂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;
}