ARC-081-F

题目

给一个$N\times M$的方格网络,有些格子是黑的,其他的是白的。你可以做选一行或者一列,将其颜色取反。操作可以做无限次。问:能得到的最大的全黑的矩形面积是多少。

数据范围

$2\leq N,M\leq 2000$

做法

对于$2\times 2$的正方形,如果内部有1个或者3个白的,那么称它为“坏的”。显然,坏的正方形不论怎么变换,仍将是坏的。所以,最后的长方形里面,一定不含有坏的正方形。显然,我们可以将长方形的最上一行和最左一列变成黑的。由于“好的”正方形,经过变换之后,一定还是好的,所以我们可以从长方形的边界推出,长方形可以变成全黑。于是,一个长方形能作为最后选择的长方形,等价条件是它不包含有坏的正方形。

将坏的正方形的中心标记为p,则问题转化为框出一个不包含p的最大的正方形,这是一个经典问题,可用悬线法$O(N\times M)$做出。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 2000 + 5;
int N, M;
char s[MAX_N];
int maze[MAX_N][MAX_N];
int b[MAX_N][MAX_N];
int l[MAX_N], r[MAX_N], h[MAX_N];
inline int check(int x, int y)
{
return maze[x][y] ^ maze[x - 1][y - 1] ^ maze[x][y - 1] ^ maze[x - 1][y];
}
int main()
{
scanf("%d%d", &N, &M);
for (int i = 1; i <= N; ++i) {
scanf("%s", s + 1);
for (int j = 1; j <= M; ++j) {
if (s[j] == '#') maze[i][j] = 1;
}
}
for (int i = 2; i <= N; ++i) {
for (int j = 2; j <= M; ++j) {
b[i][j] = check(i, j);
}
}
for (int i = 1; i <= M + 1; ++i) {
h[i] = 0;
l[i] = 1;
r[i] = M + 1;
}
int ans = 0;
for (int i = 2; i <= N + 1; ++i) {
int ll = 1, rr = M + 1;
for (int j = 1; j <= M + 1; ++j) {
if (b[i - 1][j] == 1) {
h[j] = 1;
l[j] = 1;
ll = j;
} else {
h[j] = h[j] + 1;
l[j] = max(l[j], ll);
}
}
for (int j = M + 1; j >= 1; --j) {
if (b[i - 1][j] == 1) {
r[j] = M + 1;
rr = j;
} else {
r[j] = min(r[j], rr);
}
ans = max(ans, h[j] * (r[j] - l[j]));
}
}
printf("%d\n", ans);
return 0;
}