[CodeForces-869C]The Intriguing Obsession
题目大意:
有三种颜色的点,a个红色,b个蓝色,c个紫色。
现在你要连边,保证相同颜色的点之间距离>=3,问有多少种合法的连边方案。(不一定连通)
思路:
当加上去的边不满足条件时,无非是以下两种情况:
1.同色点距离=1,同色边直接相连。
2.同色点距离=2,某个点直接连向两个不同的同色点。
我们可以将这个问题分为三个部分:
1.a个红点和b个蓝点之间的连边方案。
2.b个蓝点和c个紫点之间的连边方案。
3.a个红点和c和紫点之间的连边方案。
假设我们要在a个红色和b个蓝色之间连k条边,则总共有C(a,k)*C(b,k)*(k!)种方案。
我们最少可以连0条边,最多可以连min(a,b)条边,则只考虑红点和蓝点的总方案数为sum{C(a,k)*C(b,k)*(k!)|0<=k<=min(a,b)}。
对于三种情况都可以这样算。
显然这三种情况是不会相互影响的,因此直接将三个答案乘起来就好了。
1 #include<cstdio> 2 #include<cctype> 3 #include<algorithm> 4 typedef long long int64; 5 const int N=5001,mod=998244353; 6 inline int getint() { 7 register char ch; 8 while(!isdigit(ch=getchar())); 9 register int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return x; 12 } 13 int C[N][N]; 14 int main() { 15 for(register int i=0;i<N;i++) { 16 C[i][0]=1; 17 for(register int j=1;j<=i;j++) { 18 C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod; 19 } 20 } 21 int a=getint(),b=getint(),c=getint(); 22 int ans1=0,ans2=0,ans3=0; 23 for(register int k=0,fact=1;k<=std::min(a,b);fact=(int64)fact*++k%mod) { 24 ans1=((int64)C[a][k]*C[b][k]%mod*fact%mod+ans1)%mod; 25 } 26 for(register int k=0,fact=1;k<=std::min(b,c);fact=(int64)fact*++k%mod) { 27 ans2=((int64)C[b][k]*C[c][k]%mod*fact%mod+ans2)%mod; 28 } 29 for(register int k=0,fact=1;k<=std::min(a,c);fact=(int64)fact*++k%mod) { 30 ans3=((int64)C[a][k]*C[c][k]%mod*fact%mod+ans3)%mod; 31 } 32 printf("%d\n",int((int64)ans1*ans2%mod*ans3%mod)); 33 return 0; 34 }