「CF1608D」Dominoes - 題解
阿新 • • 發佈:2021-12-13
CF1608D 題解。
-
分析
首先,最後若干個骨牌一定滿足有 \(n\) 個黑色,\(n\) 個白色。
先考慮不存在一個骨牌上兩個格子同一個顏色的情況(即保證每個骨牌都是一黑一白)。那麼最後的染色結果一定只有 左邊都是黑色 或者 右邊都是黑色 的 2 種情況。
如果存在一個骨牌全是黑色,那麼也一定存在一個骨牌全是白色。
我們發現,用這種全黑(或白)骨牌可以將左黑右白的骨牌與左白右黑的骨牌分開,使他們合法。
也就是說,如果骨牌中存在全黑(白)骨牌,那麼剩下的顏色在滿足 \(n\) 個黑色 \(n\) 個白色的情況下,就可以隨意取。
接下來考慮初始情況。設初始給了 \(s_w\) 個白色和 \(s_b\) 個黑色。
如果初始情況存在一個全黑(白)骨牌,那麼答案即為 \(C_{2n-s_w-s_b}^{n-s_w}\) 。
如果初始不存在,用上面那個組合數再減去不合法情況即可。
即減去沒有染色出全黑(白)骨牌的所有情況,再加上 左邊都是黑色 或者 右邊都是黑色 的 2 種情況。注意一下這兩種情況是否會出現即可。
- 程式碼
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int N=2e5+5; const int Mod=998244353; int n,ans,cnt,s1,s2,cnt1,cnt2,mul[N],inv[N]; char s[N][5]; int qpow(int x,int k) { int res=1; while(k) { if(k&1)res=1ll*res*x%Mod; x=1ll*x*x%Mod; k>>=1; } return res; } int C(int x,int y){ return 1ll*mul[y]*inv[x]%Mod*inv[y-x]%Mod; } int main() { scanf("%d",&n); mul[0]=inv[0]=1; for(int i=1;i<=(N-5);i++)mul[i]=1ll*mul[i-1]*i%Mod,inv[i]=qpow(mul[i],Mod-2); for(int i=1;i<=n;i++) { scanf("%s",s[i]); cnt+=(s[i][0]!='?')+(s[i][1]!='?'); s1+=(s[i][0]=='W')+(s[i][1]=='W'); s2+=(s[i][0]=='B')+(s[i][1]=='B'); } // printf("cnt:%d s1:%d s2:%d\n",cnt,s1,s2); for(int i=1;i<=n;i++) { if(s[i][0]=='W'&&s[i][1]=='W')cnt1++; if(s[i][0]=='B'&&s[i][1]=='B')cnt2++; } // printf("C:%d %d\n",n-s1,2*n-cnt); if(cnt1||cnt2)printf("%d\n",C(n-s1,2*n-cnt)); else{ ans=C(n-s1,2*n-cnt); cnt1=cnt2=0; for(int i=1;i<=n;i++) { if(s[i][0]=='W'||s[i][1]=='B')cnt1++; if(s[i][1]=='W'||s[i][0]=='B')cnt2++; } // printf("%d\n",ans); // printf("%d %d\n",cnt1,cnt2); if(!cnt1)ans++; if(!cnt2)ans++; ans=(1ll*ans+Mod-qpow(2,n-cnt1-cnt2))%Mod; printf("%d\n",ans); } return 0; }