题意
有 N N N个点( N ≤ 1 0 5 N\leq10^5 N≤105), 第 i i i个点上有 d i d_i di个插孔( d i ≤ 1 0 9 d_i \leq 10^9 di≤109),每个插孔都是独一无二的,每条边可以连接任意两个点上的两个插孔,问有多少种不同的连边方法可以连出一棵树。
分析
设
i
i
i的度数为
d
e
g
i
deg_i
degi,则
i
i
i有
d
i
d
e
g
i
‾
d_i^{\underline{deg_i}}
didegi种不同的插孔方法。
考虑一棵树的
p
r
u
f
e
r
prufer
prufer序列,如果度数已经确定,答案为
(
n
−
2
)
!
∏
i
=
1
n
d
i
d
e
g
i
‾
(
d
e
g
i
−
1
)
!
(n-2)!\prod_{i=1}^n\frac{d_i^{\underline{deg_i}}}{(deg_i-1)!}
(n−2)!∏i=1n(degi−1)!didegi
考虑使用生成函数,设
f
i
(
x
)
=
∑
j
=
0
d
i
−
1
d
i
j
+
1
‾
j
!
x
j
f_i(x)=\sum_{j=0}^{d_i-1}\frac{d_i^{\underline{j+1}}}{j!}x^j
fi(x)=j=0∑di−1j!dij+1xj
答案为
(
n
−
2
)
!
[
x
n
−
2
]
∏
i
=
1
n
f
i
(
x
)
(n-2)![x^{n-2}]\prod_{i=1}^{n}f_i(x)
(n−2)![xn−2]i=1∏nfi(x)
化简一下式子
f
i
(
x
)
=
∑
j
=
0
d
i
−
1
d
i
!
x
j
j
!
(
d
i
−
j
−
1
)
!
=
d
i
∑
j
=
0
d
i
−
1
(
d
i
−
1
)
!
x
j
j
!
(
d
i
−
j
−
1
)
!
=
d
i
∑
j
=
0
d
i
−
1
(
d
i
−
1
j
)
x
j
=
d
i
(
x
+
1
)
d
i
−
1
\begin{aligned} f_i(x)&=\sum_{j=0}^{d_i-1}\frac{d_i!x^j}{j!(d_i-j-1)!}\\ &=d_i\sum_{j=0}^{d_i-1}\frac{(d_i-1)!x^j}{j!(d_i-j-1)!}\\ &=d_i\sum_{j=0}^{d_i-1}\binom{d_i-1}{j}x^j\\ &=d_i(x+1)^{d_i-1} \end{aligned}
fi(x)=j=0∑di−1j!(di−j−1)!di!xj=dij=0∑di−1j!(di−j−1)!(di−1)!xj=dij=0∑di−1(jdi−1)xj=di(x+1)di−1
因此答案为
(
n
−
2
)
!
[
x
n
−
2
]
∏
i
=
1
n
d
i
(
x
+
1
)
d
i
−
1
=
(
[
x
n
−
2
]
(
x
+
1
)
∑
i
=
1
n
(
d
i
−
1
)
)
(
n
−
2
)
!
∏
i
=
1
n
d
i
=
(
∑
i
=
1
n
(
d
i
−
1
)
n
−
2
)
(
n
−
2
)
!
∏
i
=
1
n
d
i
\begin{aligned} &(n-2)![x^{n-2}]\prod_{i=1}^{n}d_i(x+1)^{d_i-1}\\ =&([x^{n-2}](x+1)^{\sum_{i=1}^{n}(d_i-1)})(n-2)!\prod_{i=1}^{n}d_i\\ =&\binom{\sum_{i=1}^{n}(d_i-1)}{n-2}(n-2)!\prod_{i=1}^{n}d_i \end{aligned}
==(n−2)![xn−2]i=1∏ndi(x+1)di−1([xn−2](x+1)∑i=1n(di−1))(n−2)!i=1∏ndi(n−2∑i=1n(di−1))(n−2)!i=1∏ndi
P.S.:还可以继续化简
代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int mod=998244353;
int n,d,sum,ans=1;
int fastpow(int a,int x){
int res=1;
while(x){
if(x&1){
res=1LL*res*a%mod;
}
x>>=1;
a=1LL*a*a%mod;
}
return res;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&d);
ans=1LL*ans*d%mod;
sum=(sum+d-1)%mod;
if(i<=n-2){
ans=1LL*ans*i%mod;
}
}
if(sum<n-2){
puts("0");
return 0;
}
for(int i=1;i<=n-2;i++){
ans=1LL*ans*(sum-i+1)%mod*fastpow(i,mod-2)%mod;
}
printf("%d\n",ans);
return 0;
}