[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
",int((int64)ans1*ans2%mod*ans3%mod));
33     return 0;
34 }
原文地址:https://www.cnblogs.com/skylee03/p/7731687.html