来源:Codeforces Round #439 (Div. 2)
Vjudge地址:https://vjudge.net/problem/CodeForces-869C
1 1 1
8
1 2 2
63
1 3 5
3264
6 2 9
813023575
the second example图片如下:
由样例1可以知道,最终结果res=红蓝桥的方案数×红蓝桥的方案数×红蓝桥的方案数
那么问题就分解为求两种颜色之间小岛方案数。
样例2中,三种颜色的小岛数量分别为1,2,2.
1-2之间有3种搭桥方案(1种不搭桥,2种搭一座桥),2-2之间有7种搭桥方案(1种不搭桥,4种搭一座桥,2种搭两座桥)
故样例2输出为3×3×7=63种方案。
样例3中,三种颜色的小岛数量分别为1,3,5.
1-3之间有4种搭桥方案(1种不搭桥,3种搭一座桥),1-5之间有6种搭桥方案(1种不搭桥,5种搭一座桥),那3-5呢?
通过样例输出可以算出,3-5之间的方案数=3264÷(4×6)=136,那136怎么得来呢?
首先0座桥有1种,1座桥有3×5=15种,那2座桥是C(3,2)×C(5,2)=3×10=30种么?3座桥是C(3,3)×C(5,3)=10种么?
不是,2座桥匹配可以是11,22也可以是12,21,所以要在30的基础上乘2,
3座桥匹配可以是....
其实可以一侧固定顺序,求另一侧有多少的排列方式,数学表达即阶乘,这样就可以总结出来不同桥数的不同方案数。
3-5之间的桥方案数分别为:
0座桥:C(3,0)*C(5,0)*0!=1种
1座桥:C(3,1)*C(5,1)*1!=15种
2座桥:C(3,2)*C(5,2)*2!=60种
3座桥:C(3,3)*C(5,3)*3!=60种
故3-5之间方案数为136种,完美解释样例。
那么可以推出一般规律,设2种颜色的小岛数是a,b,它们之间建桥的方案数res。
那么2种颜色之间桥数可以从0到min(a,b).
则对于a,b,有
核心实现代码:
int A,B,C;
A=B=C=0;
int res=0;
for(int i=0;i<=min(a,b);i++)
{
A+=((comb(a,i)*comb(b,i))%MOD*F[i])%MOD;
A%=MOD;
}
for(int i=0;i<=min(c,b);i++)
{
B+=((comb(c,i)*comb(b,i))%MOD*F[i])%MOD;
B%=MOD;
}
for(int i=0;i<=min(a,c);i++)
{
C+=((comb(a,i)*comb(c,i))%MOD*F[i])%MOD;
C%=MOD;
}
//cout<<A<<" "<<B<<" "<<C<<endl;
res=A*B;
res%=MOD;
res*=C;
res%=MOD;
本题代码如下:
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 5000 + 5;
const int MOD = 998244353;
unsigned long long F[N], Finv[N], inv[N];//F是阶乘,Finv是逆元的阶乘
void init(){
inv[1] = 1;
for(int i = 2; i < N; i ++){
inv[i] = (MOD - MOD / i) * 1ll * inv[MOD % i] % MOD;
}
F[0] = Finv[0] = 1;
for(int i = 1; i < N; i ++){
F[i] = F[i-1] * 1ll * i % MOD;
Finv[i] = Finv[i-1] * 1ll * inv[i] % MOD;
}
}
unsigned long long comb(int n, int m){//comb(n, m)就是C(n, m)
if(m < 0 || m > n) return 0;
return F[n] * 1ll * Finv[n - m] % MOD * Finv[m] % MOD;
}
int main(){
init();
unsigned long long a,b,c;
unsigned long long A,B,C;
A=B=C=0;
cin>>a>>b>>c;
unsigned long long res=0;
for(int i=0;i<=min(a,b);i++)
{
A+=((comb(a,i)*comb(b,i))%MOD*F[i])%MOD;
A%=MOD;
}
for(int i=0;i<=min(c,b);i++)
{
B+=((comb(c,i)*comb(b,i))%MOD*F[i])%MOD;
B%=MOD;
}
for(int i=0;i<=min(a,c);i++)
{
C+=((comb(a,i)*comb(c,i))%MOD*F[i])%MOD;
C%=MOD;
}
//cout<<A<<" "<<B<<" "<<C<<endl;
res=A*B;
res%=MOD;
res*=C;
res%=MOD;
cout<<res<<endl;
}