棋盘制作

悬线法

悬线法是一种解决矩形问题的利器,你可以抽象为:每个点都是一个固定着针的底座,你需要求出她的活动范围。
我们开3个数组:up,ll,rr代表了左、右、上的边界,那么最后我们遍历一下所有的点就能求出最大值。

怎么求up、ll、rr?

up:如果上边的点和她反色,那么up[i][j]=up[i-1][j]+1; 否则up[i][j]=1;
ll:首先预处理出只考虑本行的情况下的边界,然后如果该点和上边的点反色,那么ll[i][j]=max(ll[i][j],ll[i-1][j])。因为显然活动范围一定是较窄的那个。
rr; 同ll,只不过要取min

注意事项:初始时 ll[i][j]、rr[i][j]设为1,up[i][j]设为1,注意之后的边界

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#define maxn 2003
#define int long long
#define SZJ signed
#include<time.h>
#define AK main
#define half (l+r)>>1
#define SDOI () 
using namespace std;
#define rep(i,a,b) for (int i=a;i<=b;++i) 
#define dep(i,a,b) for (int i=a;i>=b;i--)
#define erpe (i,a) for (int i=head[a];i!=-1;i=e[i].next)
int up[maxn][maxn],ll[maxn][maxn],rr[maxn][maxn],num[maxn][maxn],n,m; 
SZJ AK SDOI
{
    cin>>n>>m;
    rep(i,0,n) rep(j,0,m) ll[i][j]=j,rr[i][j]=j,up[i][j]=1;
    rep(i,1,n) rep(j,1,m) scanf("%lld",&num[i][j]);
    rep(i,1,n) rep(j,2,m) {if (num[i][j]!=num[i][j-1]) ll[i][j]=ll[i][j-1];} 
    rep(i,1,n) dep(j,m-1,1) {if (num[i][j]!=num[i][j+1]) rr[i][j]=rr[i][j+1];} 
    
    rep(i,2,n)
    {
        rep(j,1,m) if (num[i][j]!=num[i-1][j]) up[i][j]=up[i-1][j]+1,ll[i][j]=max(ll[i][j],ll[i-1][j]);
        rep(j,1,m) if (num[i][j]!=num[i-1][j]) rr[i][j]=min(rr[i][j],rr[i-1][j]);
    }
    int ans1=0,ans2=0;
    rep(i,1,n) rep(j,1,m)
    {
        ans1=max(ans1,min(up[i][j],rr[i][j]-ll[i][j]+1)*min(up[i][j],rr[i][j]-ll[i][j]+1));
        ans2=max(ans2,up[i][j]*(rr[i][j]-ll[i][j]+1));
    }
    cout<<ans1<<endl;
    cout<<ans2<<endl;
}
原文地址:https://www.cnblogs.com/bullshit/p/9907258.html