最大全0矩形(悬线法)

前言

今天开到一道题,luogu1169棋盘制作,发现自己不会,问了一下同学,告诉我说是普及组题,感觉自己枉为提高组选手。。。
然后学习了一波悬线法。
l [ i ] [ j ] 表示(i,j)这个点向左走碰到的第一个障碍, r [ i ] [ j ] 表示向右走碰到的第一个障碍。
h [ i ] [ j ] 即所谓的悬线,表示向上走最多能走几步,那么有一个显然的结论,最后的这个答案,一定是一条悬线向左右两边扩展得到,不然的话完全可以再向上走一步。
L [ i ] [ j ] 表示我(i,j)的这条悬线向左边碰到的第一个障碍, R [ i ] [ j ] 表示向右边碰到的第一个障碍,那么我最后的这个答案就是( R [ i ] [ j ] L [ i ] [ j ] 1) h [ i ] [ j ]
求法可能比较难以说明,直接上代码吧,非常清楚

#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<iostream>
#define LL long long
#define INF (2139062143)
#define N (2005)
using namespace std;
int n,m,x,ans1,t,ans;
int map[N][N],l[N][N],r[N][N],L[N][N],R[N][N],a[N][N],h[N][N];
template <typename T> void read(T&t) {
    t=0;
    bool fl=true;
    char p=getchar();
    while (!isdigit(p)) {
        if (p=='-') fl=false;
        p=getchar();
    }
    do {
        (t*=10)+=p-48;p=getchar();
    }while (isdigit(p));
    if (!fl) t=-t;
}
int main(){
    read(n),read(m);
    for (int i=1;i<=n;i++){
        for (int j=1;j<=m;j++){
            read(x);
            a[i][j]=x^((i+j)&1);
        }
    }
    for (int i=1;i<=n;i++){
        t=0;
        for (int j=1;j<=m;j++){
            if (a[i][j]){
                l[i][j]=t;
            }   
            else t=j,L[i][j]=0;
        }
        t=m+1;
        for (int j=m;j>1;j--){
            if (a[i][j]){
                r[i][j]=t;      
            }
            else t=j,R[i][j]=m+1;
        }
    } 
    for (int i=1;i<=m;i++) L[0][i]=0,R[0][i]=m+1;
    for (int i=1;i<=n;i++){
        for (int j=1;j<=m;j++){
            if (a[i][j]){
                h[i][j]=h[i-1][j]+1;
                L[i][j]=max(L[i-1][j],l[i][j]);
                R[i][j]=min(R[i-1][j],r[i][j]);
                ans=max(ans,(R[i][j]-L[i][j]-1)*h[i][j]);
                int tt=min(R[i][j]-L[i][j]-1,h[i][j]);
                ans1=max(ans1,tt*tt);
            }
            else h[i][j]=0;
        }
    }
    memset(l,0,sizeof(l));
    memset(r,0,sizeof(r));
    memset(L,0,sizeof(L));
    memset(R,0,sizeof(R));
    memset(h,0,sizeof(h)); 
    for (int i=1;i<=n;i++){
        t=0;
        for (int j=1;j<=m;j++){
            if (!a[i][j]){
                l[i][j]=t;
            }   
            else t=j,L[i][j]=0;
        }
        t=m+1;
        for (int j=m;j>1;j--){
            if (!a[i][j]){
                r[i][j]=t;      
            }
            else t=j,R[i][j]=m+1;
        }
    } 
    for (int i=1;i<=m;i++) L[0][i]=0,R[0][i]=m+1;
    for (int i=1;i<=n;i++){
        for (int j=1;j<=m;j++){
            if (!a[i][j]){
                h[i][j]=h[i-1][j]+1;
                L[i][j]=max(L[i-1][j],l[i][j]);
                R[i][j]=min(R[i-1][j],r[i][j]);
                ans=max(ans,(R[i][j]-L[i][j]-1)*h[i][j]);
                int tt=min(R[i][j]-L[i][j]-1,h[i][j]);
                ans1=max(ans1,tt*tt);
            }
            else h[i][j]=0;
        }
    }
    printf("%d\n%d",ans1,ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36056315/article/details/80216203