「CF1608D」Dominoes - 题解

  • 分析

    首先,最后若干个骨牌一定满足有 \(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;
}
posted @ 2021-12-13 18:42  Rainy7  阅读(159)  评论(0编辑  收藏  举报