题意
给定一个01矩阵,可以给每一行/每一列整体取反,求能得到的最大全1矩阵
分析
考虑 2 ∗ 2 2*2 2∗2的矩阵,可以通过操作得到全1矩阵当且仅当有偶数个1
尝试推广这个结论,对于一个 n ∗ m n*m n∗m的矩阵,我们可以先把第一行第一列全变成1。而且整行整列的取反不会影响任意一个 2 ∗ 2 2*2 2∗2矩阵中1的奇偶性,所以一个 n ∗ m n*m n∗m的矩阵以变为全1的充要条件为任意一个 2 ∗ 2 2*2 2∗2的矩阵有偶数个1
那么我们把每个
2
∗
2
2*2
2∗2矩阵是否为全1记在左上角,问题就转换成了求最大全1矩阵 【单调栈】P4147 玉蟾宫
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2005;
int n,m;
int f[maxn][maxn];
int st[maxn],top;
int len[maxn],h[maxn];
char c[maxn][maxn];
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%s",c[i]+1);
for(int i=1;i<n;i++)
for(int j=1;j<m;j++)
{
int gs=0;
if(c[i][j]=='#') gs++;
if(c[i][j+1]=='#') gs++;
if(c[i+1][j]=='#') gs++;
if(c[i+1][j+1]=='#') gs++;
if(gs&1) f[i][j]=0;
else f[i][j]=f[i-1][j]+1;
}
int ans=max(n,m);
n--; m--;
for(int i=1;i<=n;i++)
{
top=1; len[1]=1; h[1]=f[i][1];
ans=max(ans,h[1]);
for(int j=2;j<=m;j++)
{
int w=0;
while(top && h[top]>=f[i][j])
{
w+=len[top];
ans=max(ans,(w+1)*(h[top]+1));
top--;
}
top++; h[top]=f[i][j]; len[top]=w+1;
}
int w=0;
while(top)
{
w+=len[top];
ans=max(ans,(w+1)*(h[top]+1));
top--;
}
}
printf("%d",ans);
return 0;
}