AT2699 [ARC081D] Flip and Rectangles

以下是简要题解:

  1. 首先思考如何判定一个矩形是否能通过操作变成全黑。

  2. 首先从简单而又特殊的 \(2 \times 2\) 的矩形开始,不难发现只要其中黑色数量不为奇数即可。

  3. 近一步拓展可以发现,一个矩形合法当且仅当所有 \(2 \times 2\) 的矩形均满足黑色数量不为奇数。

  4. 充分性显然,必要性证明思路如下:显然通过任意的操作不会改变 \(2 \times 2\) 子矩形黑色数量为偶数个的性质,通过构造一定能使得第一行第一列一定为黑色,那么根据一个矩形内部黑色数量不为奇数,必定可以推出矩形全黑。

  5. 于是问题就转化成:将 \(2 \times 2\) 的偶数数量矩形缩成点标号为 \(1\),否则标号为 \(0\),求最大全 \(1\) 子矩阵的大小。

  6. 这是一个经典问题,枚举底面就可以变成一个经典的一维单调栈问题。

要注意的是,单独一行或一列不存在 \(2 \times 2\) 的子矩形但都是可以变成全黑的。

#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l; i <= r; ++i)
#define dep(i, l, r) for (int i = r; i >= l; --i)
const int N = 2e3 + 5;
char s[N][N]; int n, m, top, ans, l[N], r[N], h[N], st[N], a[N][N];
int calc(int x, int y) { 
    return (s[x][y] == '#') + (s[x + 1][y] == '#') + (s[x][y + 1] == '#') + (s[x + 1][y + 1] == '#');
}
int main () {
    cin >> n >> m;
    rep(i, 1, n) scanf("%s", s[i] + 1);
    rep(i, 1, n - 1) rep(j, 1, m - 1) if(calc(i, j) % 2 == 0) a[i][j] = 1;
    --n, --m;
    rep(i, 1, n) {
        memset(l, 0, sizeof(l)), memset(r, 0, sizeof(r));
        rep(j, 1, m) h[j] = a[i][j] * h[j] + a[i][j];
        top = 0;
        dep(j, 1, m) {
            for (; top && h[st[top]] > h[j]; --top) l[st[top]] = j;
            st[++top] = j;
        }
        top = 0;
        rep(j, 1, m) {
            for (; top && h[st[top]] > h[j]; --top) r[st[top]] = j;
            st[++top] = j;
        }
        rep(j, 1, m) if(!r[j]) r[j] = m + 1;
        rep(j, 1, m) ans = max(ans, (h[j] + 1) * (r[j] - l[j]));
    }
    printf("%d", max(ans, max(n + 1, m + 1)));
    return 0;
}

因为题目要求最大的能被涂成全黑的矩形,最朴素的想法判定一个矩形能被涂黑是非常重要的。

直接判定是不好判定的,可以从一些小而特殊的情况开始考虑,再观察一般情况与特殊情况的联系与区别。

同时,可以观察判定的必要条件,往往通过一些必要条件的组合就能推出判定的充分条件。

posted @ 2020-11-21 20:00  Achtoria  阅读(87)  评论(0编辑  收藏  举报