qoj #17733. Tromino 铺设 题解

这种确定一个中心点必须要放一个 \(L\) 型联通块,非常重要的一个转化就是,把相邻的四个点分成相对的两组每组必须选一个,这是等价的。然后发现变成了什么,对于每个中心点把每组的两个点连一条边,最后建成图,于是最后转化为“为每个边都匹配一个端点,有些端点被ban了,每个端点只能用一次的方案数”。只需要对每个联通块的方案数累乘即可。

1.树,ban掉 \(>=2\) 个点的答案是 \(0\) ,ban掉 \(1\) 个点的答案是 \(1\) ,ban掉 \(0\) 个点的答案是 \(siz\) 。
2.点数 \(=\) 边数,ban掉 \(>=1\) 个点的答案是 \(0\) ,ban掉 \(0\) 个点的答案是 \(2\) 。
3.点数 \(<\) 边数,答案就是 \(0\) 。

至于最后咋维护, \(DFS\) 或者并查集啥的简单维护一下就行,复杂度 \(O(n)\) 。
代码:

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 1010;
const int Mod = 1e9+7;
int n, m;
char g[N][N];
int pre[N * N], cnt[N * N], cnt_e[N * N], cnt_p[N * N];
inline int turn(int x, int y) {
    y++;
    return x * (m + 2) + y;
}
inline void init() {
    for (int i = 0; i <= n + 1; i++) {
        for (int j = 0; j <= m + 1; j++) {
            int num = turn(i, j);
            pre[num] = num;
            cnt[num] = 1;
            cnt_e[num] = 0;
            cnt_p[num] = (g[i][j] != '.');
        }
    }
}
inline int find(int x) {
    if (x == pre[x])
        return x;

    return pre[x] = find(pre[x]);
}
inline void merge(int x, int y) {
    x = find(x);
    y = find(y);

    if (x == y) {
        cnt_e[x]++;
        return ;
    }

    if (cnt[x] > cnt[y])
        swap(x, y);

    pre[x] = y;
    cnt[y] += cnt[x];
    cnt_p[y] += cnt_p[x];
    cnt_e[y] += cnt_e[x] + 1;
}
inline void solve() {
    cin >> n >> m;

    for (int i = 0; i <= n + 1; i++) {
        for (int j = 0; j <= m + 1; j++) {
            if (i < 1 || i > n || j < 1 || j > m)
                g[i][j] = '#';
            else
                cin >> g[i][j];
        }
    }

    init();

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (g[i][j] == 'o') {
                merge(turn(i + 1, j), turn(i - 1, j));
                merge(turn(i, j + 1), turn(i, j - 1));
            }
        }
    }

    ll ans = 1;

    for (int i = 1; i <= (n + 2) * (m + 2); i++) {
        if (pre[i] != i || cnt[i] == 1)
            continue;

        if (cnt[i] < cnt_e[i])
            ans = 0;
        else if (cnt[i] == cnt_e[i]) {
            if (cnt_p[i])
                ans = 0;
            else
                ans = ans * 2 % Mod;
        } else {
            if (cnt_p[i] == 0)
                ans = ans * cnt[i] % Mod;
            else if (cnt_p[i] > 1)
                ans = 0;
        }
    }

    cout << ans << '\n';
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin >> T;

    while (T--)
        solve();

    return 0;
}```
posted @ 2026-10-10 12:39  bjq521  阅读(4)  评论(0)    收藏  举报