[组合数学] Codeforces 1608D Dominoes
题目大意
给你 \(n\) 张卡牌,每张卡牌有左边和右边两个格子,可以涂上红色或蓝色。一开始有些格子被涂了颜色,有些没有涂。要求给卡牌的格子涂完色,使得最终可以通过合理安排卡牌的顺序,使得第 \(i\) 张卡牌的右边格子和第 \((i\ \mathrm{mod}\ n)+1\) 张卡牌的左边格子不同色,卡牌不能左右翻转。求涂色方案数模 \(998244353\)。
题解
首先,蓝色格子的数量和红色格子的数量一定要相同。在满足这一限制的条件下,若同时有一张 WW
和 BB
,则剩下卡牌的涂色是任意的,因为无论怎么涂,总能插入WW BB
这个环中。但若没有 WW
和 BB
,则只有两种情况,要么全为 WB
,要么全为 BW
。于是我们可以算出蓝色和红色格子数量相等时任意涂色的方案数,再减去不含有 BB
和 WW
的方案数,再加上全为 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;
}