QOJ.ac

QOJ

Type: Editorial

Status: Open

Posted by: Lynn_Sue

Posted at: 2026-07-17 12:59:58

Last updated: 2026-07-17 13:17:21

Back to Problem

打角 2.0 题解

原来是图论题吗。

考虑对一个 * 选骨牌意味着什么。它等价于上下选一格左右选一格。

然后考虑建图。二选一的建边。如果一个 * 某一方的 . 是固定的可以建自环。

对每一个连通块,其实就是对每条边选一个点,分类讨论:

  • 如果有自环,方案数为 $1$。

  • 否则如果是基环树,方案数为 $2$。

  • 如果是树,方案数为节点数。

  • 否则不合法,方案数为 $0$。

乘法原理即可。可以用并查集维护。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int t, n, m, f[100005], cnt[100005], siz[100005];
bool sc[100005];
const int mod = 998244353;
string s[1005];
const int dx[] = {0, 1, -1, 0, 0}, dy[] = {0, 0, 0, 1, -1};
int tid(int x, int y){
    return (x - 1) * m + y;
}
int find(int x){
    if (f[x] == x)
        return x;
    return f[x] = find(f[x]);
}
void merge(int u, int v){
//    cerr << u << " " << v << "\n";
    int fu = find(u), fv = find(v);
    if (fu == fv){
        if (u == v)
            sc[fu] = 1;
        ++cnt[fu];
        return;
    }
    f[fv] = fu;
    cnt[fu] += cnt[fv] + 1;
    siz[fu] += siz[fv];
    sc[fu] |= sc[fv];
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin >> t;
    while (t--){
        cin >> n >> m;
        s[0] = s[n + 1] = "";
        for (int i = 1; i <= m + 2; i++){
            s[0] += "*";
            s[n + 1] += "*";
        }
        for (int i = 1; i <= n; i++){
            cin >> s[i];
            s[i] = "*" + s[i] + "*";
        }
        for (int i = 1; i <= n * m; i++)
            f[i] = i, siz[i] = 1, cnt[i] = 0, sc[i] = 0;
        int ans = 1;
        for (int i = 1; i <= n; i++){
            for (int j = 1; j <= m; j++){
                if (s[i][j] != '*')
                    continue;
                if (s[i + dx[1]][j + dy[1]] == '.' && s[i + dx[2]][j + dy[2]] == '.')
                    merge(tid(i + dx[1], j + dy[1]), tid(i + dx[2], j + dy[2]));
                else if (s[i + dx[1]][j + dy[1]] == '.')
                    merge(tid(i + dx[1], j + dy[1]), tid(i + dx[1], j + dy[1]));
                else if (s[i + dx[2]][j + dy[2]] == '.')
                    merge(tid(i + dx[2], j + dy[2]), tid(i + dx[2], j + dy[2]));
                else
                    ans = 0;
                if (s[i + dx[3]][j + dy[3]] == '.' && s[i + dx[4]][j + dy[4]] == '.')
                    merge(tid(i + dx[3], j + dy[3]), tid(i + dx[4], j + dy[4]));
                else if (s[i + dx[3]][j + dy[3]] == '.')
                    merge(tid(i + dx[3], j + dy[3]), tid(i + dx[3], j + dy[3]));
                else if (s[i + dx[4]][j + dy[4]] == '.')
                    merge(tid(i + dx[4], j + dy[4]), tid(i + dx[4], j + dy[4]));
                else
                    ans = 0;
            }
        }
        for (int i = 1; i <= n * m; i++){
            if (find(i) == i){
                if (cnt[i] >= siz[i] + 1)
                    ans = 0;
                else if (sc[i] && cnt[i] == siz[i])
                    ans = ans;
                else if (cnt[i] == siz[i])
                    ans = (ans + ans) % mod;
                else
                    ans = (1ll * ans * siz[i]) % mod;
            }
        }
        cout << ans << "\n";
    }
    return 0;
}

Comments

No comments yet.