题目链接:http://codeforces.com/problemset/problem/869/C
题意:
红色、蓝色、紫色的小岛分别有a,b,c个。
你可以在两个不同的岛之间架桥,桥的长度为1。
任意两个颜色相同的岛之间的距离不能小于3。
问你合法的架桥方案数。
题解:
显然只能在不同颜色的岛之间连边。
而且一个岛对于一种颜色,最多只能连一个岛。
设f(x,y)表示两种颜色的岛相互连边,分别有x,y个,连边的方案数。(x < y)
那么ans = f(a,b) * f(b,c) * f(a,c)
解法1(组合数):
枚举共连了k条边,k∈[1,x]。
那么连了k条边的方案数 = C(x,k) * C(y,k) * k!
总方案数f(x,y) = ∑(C(x,k) * C(y,k) * k!)
解法2(dp):
向其中A集合中加入一个岛,要么不连边,要么根B集合中的任意一个点连边(共j种方案)。
f(i,j) = f(i-1,j) + f(i-1,j-1)*j
AC Code(combination):
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #define MAX_N 5005 5 #define MOD 998244353 6 7 using namespace std; 8 9 int mx=0; 10 int a[3]; 11 long long f[MAX_N]; 12 long long c[MAX_N][MAX_N]; 13 long long ans=1; 14 15 void cal_f() 16 { 17 f[0]=1; 18 for(int i=1;i<=mx;i++) f[i]=f[i-1]*i%MOD; 19 } 20 21 void cal_c() 22 { 23 c[0][0]=1; 24 for(int i=1;i<=mx;i++) 25 { 26 c[i][0]=1; 27 for(int j=1;j<=i;j++) 28 { 29 c[i][j]=(c[i-1][j-1]+c[i-1][j])%MOD; 30 } 31 } 32 } 33 34 int main() 35 { 36 for(int i=0;i<3;i++) 37 { 38 cin>>a[i]; 39 mx=max(mx,a[i]); 40 } 41 cal_f(); 42 cal_c(); 43 for(int i=0;i<3;i++) 44 { 45 for(int j=i+1;j<3;j++) 46 { 47 int x=min(a[i],a[j]); 48 int y=max(a[i],a[j]); 49 int sum=0; 50 for(int k=0;k<=x;k++) 51 { 52 sum=(sum+c[x][k]*c[y][k]%MOD*f[k])%MOD; 53 } 54 ans=ans*sum%MOD; 55 } 56 } 57 cout<<ans<<endl; 58 }
AC Code(dp):
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #define MAX_N 5005 5 #define MOD 998244353 6 7 using namespace std; 8 9 int a,b,c; 10 long long dp[MAX_N][MAX_N]; 11 12 int main() 13 { 14 cin>>a>>b>>c; 15 int mx=max(a,max(b,c)); 16 for(int i=0;i<=mx;i++) 17 { 18 dp[i][0]=dp[0][i]=1; 19 } 20 for(int i=1;i<=mx;i++) 21 { 22 for(int j=1;j<=mx;j++) 23 { 24 dp[i][j]=(dp[i-1][j]+dp[i-1][j-1]*j)%MOD; 25 } 26 } 27 cout<<dp[a][b]*dp[b][c]%MOD*dp[a][c]%MOD<<endl; 28 }