CF1608D Dominoes (2400) (组合数学)

https://codeforces.com/contest/1608/problem/D

  • B,W 都要出现n次。
  • 如果出现BB或WW的话,一定可以通过调整站位摆出合法情况。
  • 如果没有BB或WW的话,画一下例子我们发现,所有牌必须是相同的涂色:都是BW或都是WB,否则一定矛盾。
  • \(ans = \binom{2 * n - cntW - cntB}{n - cntW} - cal\) cal是有且只有BW,WB的情况数。
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
typedef long long ll;
const int N = 2e5 + 5;
const int mod = 998244353;
char ss[N][3];
ll F[N], inv[N];
ll qmi(ll m, ll k) {
   ll res = 1 % mod;
   while (k){
       if(k & 1) res = res * m % mod;
       m = m * m % mod;
       k >>= 1;
   }
   return res;
}
void init() {
   int n = 200000;
   F[0] = inv[0] = 1;
   for(int i = 1; i <= n; ++ i) F[i] = F[i - 1] * i % mod;
   inv[n] = qmi(F[n], mod - 2);
   for(int i = n - 1; i >= 1; -- i) inv[i] = inv[i + 1] * (i + 1) % mod;
}
ll C(ll n, ll m) {

   return F[n] * inv[m] % mod * inv[n - m] % mod;
}
int main() {
   init();
   ll n; scanf("%lld", &n);
   ll cntW = 0, cntB = 0;
   for (int i = 1; i <= n; ++ i) {
       scanf(" %s", ss[i]);
       if(ss[i][0] == 'W') ++ cntW; if(ss[i][1] == 'W') ++ cntW;
       if(ss[i][0] == 'B') ++ cntB; if(ss[i][1] == 'B') ++ cntB;
   }
   if (cntW > n || cntB > n) {
       cout << 0 << '\n'; return 0;
   }
   ll ans = C(2 * n - cntB - cntW, n - cntB);
   ll cal = 1;
   int ok1 = 1, ok2 = 1; //能否达成全BW,全WB
   for (int i = 1; i <= n; ++ i) {
       if(ss[i][0] == '?' && ss[i][1] =='?') cal = cal * 2 % mod;
       if(ss[i][0] == ss[i][1] && ss[i][0] != '?') { //出现WW,BB就不用再减了
           cal = 0; ok1 = ok2 = 0;
       }
       if(ss[i][0] == 'B' || ss[i][1] =='W') ok1 = 0; if(ss[i][0] == 'W' || ss[i][1] == 'B') ok2 = 0; 
   }

   ans = ((ans - cal + mod) % mod + ok1 + ok2) % mod; 
   
   cout << ans << '\n'; 
   return 0;
}
posted @ 2022-03-18 11:18  qingyanng  阅读(24)  评论(0编辑  收藏  举报