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);
}