ARC081F Flip and Rectangles

题意简述:给你一个\(n*m\ (n,m<=2000)\)的0/1矩阵,可以多次将一行或一列所有值xor 1,求最终能得到的最大全1子矩形。

wdnmd。。看完题毛想法都没有,这就是ARC吗?

然后orz了yls的blog,发现有一个奇怪的性质,就是对于一个\(2*2\)的子矩阵,若其1的数量为偶数,那么这个子矩阵可以被转为全1的。

然后我们考虑在一个合法的子矩阵中,先通过翻转将第一行全部变为1,由于操作不改变\(2*2\)子矩阵中1数量的奇偶性,那么剩下的行要么全为0,要么全为1,再把全0行翻转一次即可。

所以我们可以将每个点的值改为以其为左上角的\(2*2\)的子矩阵的异或值,问题变为了求最大全0子矩阵了。

使用悬线法/单调栈可做到\(O(n^2)\)

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=2010;
int n,m,ans,a[N][N],up[N],L[N],R[N];
char s[N];
int main(){
    scanf("%d%d",&n,&m);ans=max(n,m);
    for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        for(int j=1;j<=m;j++)
            a[i][j]=s[j]=='.'?0:1;
    }
    --n;--m;
    for(int i=1;i<=m;i++)L[i]=1,R[i]=m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            a[i][j]^=a[i+1][j]^a[i][j+1]^a[i+1][j+1];
    for(int i=1;i<=n;i++){
        int l=0,r=m+1;
        for(int j=1;j<=m;j++)
            if(a[i][j])up[j]=0,l=j,L[j]=1;
            else ++up[j],L[j]=max(L[j],l+1);
        for(int j=m;j;j--)
            if(a[i][j])r=j,R[j]=m;
            else {
                R[j]=min(R[j],r-1);
                ans=max((R[j]-L[j]+2)*(up[j]+1),ans);
            }
    }
    printf("%d\n",ans);
}

posted @ 2019-04-14 20:05  努力进步的肥宅yxc  阅读(168)  评论(0编辑  收藏  举报