Flip and Rectangles
题意
ARC081D
给 \(n \times m(n,m\leq 2000)\) 的 01 矩阵, 每次可以翻转一行或一列颜色, 求可能的最大 1 子矩阵的面积。
转化
考虑要求一个子矩阵全是 1。
对于其中一点 \((x, y)\), 如果为 0 那么就对这行翻转,使它为 1。
如果 \((x, k), (k, y), k \in Z\) 的格子是 0 就使对应的行或列翻转。
现在 \(x\) 行 和 \(y\) 列的格子都是 1,如果再对子矩阵的任何行列操作都会使它们变化。
这就代表无法操作了。
对于任意 \(i \neq x, j \neq y\), 会可能会被 \(x\) 行的格子翻转或者 \(y\) 列的格子翻转,具体要满足的条件是 \(!a_{x, y} \oplus !a_{x, j}\) 和 \(!a_{i, y}\)。
就要满足: \(!a_{x, y} \oplus !a_{x, j} \oplus !a_{i, y} \oplus a_{i,j} = 1\)
等价于: \(1 \oplus a_{x, y} \oplus 1 \oplus a_{x, j} \oplus 1 \oplus a_{i, y} \oplus a_{i, j} = 1 \oplus 1 \oplus 1 \oplus 1\)
即: \(a_{x, y} \oplus a_{x, j} \oplus a_{i, y} \oplus a_{i, j} = 0\)
发现 \(x, y, i, j\) 的取值是较松的,当取到 \(2 \times 2\) 的子矩阵时,只要子矩阵内的所有 \(2 \times 2\) 的子矩阵都满足这个性质,代表它能翻到全黑。
于是对于 \(2 \times 2\) 个点缩成一个点,满足上述限制就为 \(1\), 否则为 \(0\), 就得到 \((n - 1) \times (m - 1)\) 的新矩阵。
问题就转化为是矩形内全是1的矩阵的最大面积。
要注意答案最小也可以是 \(\min{n, m}\)。
悬线法
悬线就是上到下的线,考虑左右能最远到的地方。
具体就是当前位置往左往右最大的矩阵。
代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2050;
const int INF = 0x7fffffff;
const int mod = 1000000007;
using ll = long long;
template <typename T>
void Read(T &x) {
x = 0; T f = 1; char a = getchar();
for(; a < '0' || '9' < a; a = getchar()) if (a == '-') f = -f;
for(; '0' <= a && a <= '9'; a = getchar()) x = (x * 10) + (a ^ 48);
x *= f;
}
int n, m;
char a[MAXN][MAXN];
int b[MAXN][MAXN], l[MAXN][MAXN], r[MAXN][MAXN], L[MAXN][MAXN], R[MAXN][MAXN], h[MAXN][MAXN];
int main() {
Read(n); Read(m);
for (int i = 1; i <= n; i ++) {
cin >> a[i] + 1;
}
for (int i = 1; i < n; i ++)
for (int j = 1; j < m; j ++)
b[i][j] = ((a[i][j] == '#') + (a[i][j + 1] == '#') + (a[i + 1][j] == '#') + (a[i + 1][j + 1] == '#')) % 2 == 0;
int ans = max(n, m);
n --, m --;
for (int i = 1; i <= n; i ++) {
int lst = 0;
for (int j = 1; j <= m; j ++)
if (b[i][j]) l[i][j] = lst;
else L[i][j] = 0, lst = j;
lst = m + 1;
for (int j = m; j >= 1; j --)
if (b[i][j]) r[i][j] = lst;
else R[i][j] = m + 1, lst = j;
}
for (int i = 1; i <= m; i ++)
R[0][i] = m + 1;
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++) {
if (b[i][j]) {
h[i][j] = h[i - 1][j] + 1;
L[i][j] = max(l[i][j] + 1, L[i - 1][j]);
R[i][j] = min(r[i][j] - 1, R[i - 1][j]);
ans = max(ans, (h[i][j] + 1)* (R[i][j] - L[i][j] + 1 + 1));
}
}
cout << ans << endl;
return 0;
}