ABC 432 D题's 题解

标签:模拟

前言

根据数据范围判断算法,整体思维锻炼

正文

格式化题目

现在有一个无限大小的网格,一开始矩阵 \([(0,X-1),(Y-1,0)]\) 为黑色 \((X,Y\le 10^8)\),其他地方均为白色,给出 \(N(\le14)\) 次操作,每次操作形式如下:

  • \(X~a~b\) 表示将纵轴小于 \(a\) 的点整体向下平移 \(b\) 个单元格,纵轴大于等于 \(a\) 的点整体向上平移 \(b\) 个单元格
  • \(Y~a~b\) 表示将横轴小于 \(a\) 的点整体像左平移 \(b\) 个单元格,横轴大于等于 \(a\) 的点整体向右平移 \(b\) 个单元格

问,最后黑色的单元格构成了几个联通块?(以四联通为准)

思路(题解)

发现 \(N\) 特别小,可以从这个地方入手,但是我们又发现不好拿现有的数据结构维护这个联通块信息,像这种情况(操作次数小,操作不好维护)就可以考虑是大模拟,怎么模拟呢?

关键发现:

  1. 操作后不可能会出现重叠的联通块
  2. 所有联通块均为长方形

证明(先只考虑第一个操作,因为经过旋转后能把第二个操作变成第一个操作):

  1. 每次操作是根据一个 \(X\) 轴上的一个分界线进行两个不同的操作,所以从这个分界线分开,其他的点都是平移,不会改变相对位置,所以永远都不会有重叠
  2. 根据第一个能够看出最多把一个矩形变成两个相错的矩形,所以形状也不会有改变

所以用一个结构体,维护每一个矩形的四个坐标,每次操作就把这个矩形按照正常的操作分成两个矩形(先不考虑连通块),最后最多得到 \(2^N\) 个矩形,由于 \(N\) 足够小,所以没有问题,之后再判断有没有有公共边的矩形,再用并查集合起来,就能够得到答案了。

时间复杂度: \(\Theta(2^{2N})\)

空间复杂度: \(\Theta(2^N)\)

代码

#include <cstdio>
#include <vector>
#include <algorithm>
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int MAXSZ = 1 << 20;
char ch, buf[MAXSZ], *p1, *p2;
#define ge() (p1 == p2 && (p2 = buf + fread(p1 = buf, 1, MAXSZ, stdin), p1 == p2) ? EOF : *p1++)
template <typename T_T>
inline void read(T_T &x) {
    x = 0;
    bool flag = true;

    while (ch < '0' || '9' < ch) {
        ch = ge();
        if (ch == '-') flag = false;
    }
    while ('0' <= ch && ch <= '9') {
        x = x * 10 + (ch ^ 48);
        ch = ge();
    }

    if (!flag)
        x = -x;
}
template <typename T_T>
inline void write(T_T x) {
    if (x < 0) {
        putchar('-');
        x = -x;
    }

    if (x > 9) write(x / 10);
    putchar(x % 10 | 48);
}
template <typename T_T>
inline void swap(T_T &x, T_T &y) {
    x ^= y;
    y ^= x;
    x ^= y;
}

const int N = 1 << 15;
struct Node {
    ll xa, ya, xb, yb;
};
ll X, Y, sz[N], ans[N];
std::vector <Node> k, tmp_k;
int n, fa[N], cnt;

int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
void merge(int x, int y) {
    x = find(x), y = find(y);
    if (x == y) return ;
    if (sz[x] > sz[y]) swap(x, y);

    fa[x] = y;
    sz[y] += sz[x];
}
bool check1(int i, int j) {return (k[i].xa <= k[j].xa && k[j].xa <= k[i].xb) && (k[i].yb == k[j].ya + 1 || k[j].yb == k[i].ya + 1);}
bool check2(int i, int j) {return (k[i].ya >= k[j].ya && k[j].ya >= k[i].yb) && (k[i].xa - 1 == k[j].xb || k[j].xa - 1 == k[i].xb);}

int main() {
    read(n), read(X), read(Y);
    k.emplace_back((Node){0, Y - 1, X - 1, 0});

    while (n --) {
        char ch = ge();
        ll a, b; read(a), read(b);

        tmp_k.clear();
        for (auto k1 : k) {
            if (ch == 'X') {
                if (k1.xb < a) tmp_k.emplace_back((Node){k1.xa, k1.ya - b, k1.xb, k1.yb - b});
                if (k1.xa >= a) tmp_k.emplace_back((Node){k1.xa, k1.ya + b, k1.xb, k1.yb + b});
                if (k1.xa < a && k1.xb >= a) {
                    tmp_k.emplace_back((Node){k1.xa, k1.ya - b, a - 1, k1.yb - b});
                    tmp_k.emplace_back((Node){a, k1.ya + b, k1.xb, k1.yb + b});
                }
            }
            else {
                if (k1.ya < a) tmp_k.emplace_back((Node){k1.xa - b, k1.ya, k1.xb - b, k1.yb});
                if (k1.yb >= a) tmp_k.emplace_back((Node){k1.xa + b, k1.ya, k1.xb + b, k1.yb});
                if (k1.ya >= a && k1.yb < a) {
                    tmp_k.emplace_back((Node){k1.xa - b, a - 1, k1.xb - b, k1.yb});
                    tmp_k.emplace_back((Node){k1.xa + b, k1.ya, k1.xb + b, a});
                }
            }
        }

        k = tmp_k;
    }

    for (int i = 0; i < k.size(); i++) fa[i] = i, sz[i] = (k[i].xb - k[i].xa + 1) * (k[i].ya - k[i].yb + 1);
    for (int i = 0; i < k.size(); i++)
        for (int j = i + 1; j < k.size(); j++)
            if (check1(i, j) || check2(i, j) || check1(j, i) || check2(j, i))
                merge(i, j);

    for (int i = 0; i < k.size(); i++)
        if (fa[i] == i)
            ans[++ cnt] = sz[i];
    std::sort(ans + 1, ans + cnt + 1);

    write(cnt), putchar('\n');
    for (int i = 1; i <= cnt; i++)
        write(ans[i]), putchar(' ');
    putchar('\n');
    return 0;
}
posted @ 2026-04-05 23:02  Ryan_L_F  阅读(3)  评论(0)    收藏  举报