[组合数学] Codeforces 1608D Dominoes

题目大意

给你 \(n\) 张卡牌,每张卡牌有左边和右边两个格子,可以涂上红色或蓝色。一开始有些格子被涂了颜色,有些没有涂。要求给卡牌的格子涂完色,使得最终可以通过合理安排卡牌的顺序,使得第 \(i\) 张卡牌的右边格子和第 \((i\ \mathrm{mod}\ n)+1\) 张卡牌的左边格子不同色,卡牌不能左右翻转。求涂色方案数模 \(998244353\)

题解

首先,蓝色格子的数量和红色格子的数量一定要相同。在满足这一限制的条件下,若同时有一张 WWBB,则剩下卡牌的涂色是任意的,因为无论怎么涂,总能插入WW BB 这个环中。但若没有 WWBB,则只有两种情况,要么全为 WB,要么全为 BW。于是我们可以算出蓝色和红色格子数量相等时任意涂色的方案数,再减去不含有 BBWW 的方案数,再加上全为 WB 或全为 BW 的方案数,即为答案。

Code

#include <bits/stdc++.h>
using namespace std;

#define LL long long
const LL MOD = 998244353;
LL inv[200010], fact[200010], finv[200010];
string s[100010];
map<string, int> mp;
int cnt[2];
int n;

void Init() {
    inv[1] = fact[0] = fact[1] = finv[0] = finv[1] = 1;
    for (int i = 2;i <= 200000;++i) {
        inv[i] = ((-(MOD / i) * inv[MOD % i]) % MOD + MOD) % MOD;
        fact[i] = fact[i - 1] * i % MOD;
        finv[i] = finv[i - 1] * inv[i] % MOD;
    }
}

LL qpow(LL b, LL n) {
    LL x = 1, Power = b % MOD;
    while (n) {
        if (n & 1) x = x * Power % MOD;
        Power = Power * Power % MOD;
        n >>= 1;
    }
    return x;
}

int main() {
    Init();
    ios::sync_with_stdio(false);
    cin >> n;
    for (int i = 1;i <= n;++i) { cin >> s[i]; ++mp[s[i]]; }
    for (int i = 1;i <= n;++i) {
        if (s[i][0] == 'W') ++cnt[0];
        else if (s[i][0] == 'B') ++cnt[1];
        if (s[i][1] == 'W') ++cnt[0];
        else if (s[i][1] == 'B') ++cnt[1];
    }
    if (cnt[0] > n || cnt[1] > n) { cout << 0 << endl; return 0; }
    LL ans = fact[n * 2 - cnt[0] - cnt[1]] * finv[n - cnt[0]] % MOD * finv[n - cnt[1]] % MOD;
    if (mp.count("BB") || mp.count("WW")) { cout << ans << endl; return 0; }
    ans = ((ans - qpow(2, mp["??"])) % MOD + MOD) % MOD;
    if (!mp.count("BW") && !mp.count("B?") && !mp.count("?W")) ++ans;
    if (!mp.count("WB") && !mp.count("W?") && !mp.count("?B")) ++ans;
    ans %= MOD;
    cout << ans << endl;

    return 0;
}
posted @ 2022-01-05 15:12  AE酱  阅读(81)  评论(0编辑  收藏  举报