洛谷P2624 [HNOI2008]明明的烦恼(Prufer序列+组合数学)
**题目:**给你n个节点的树中某些节点的度数,其他节点的度数任意,问有多少种满足题意的树。
思路:
假设给出n个节点的K个节点度数确定,且分别为 d 1 , d 2 , d 3 . . . d k d_1,d_2,d_3...d_k d1,d2,d3...dk。我们令 a i = d i − 1 a_i=d_i-1 ai=di−1, 且设 s u m = ∑ i = 1 k a i sum= \sum _{i=1} ^{k}a_i sum=∑i=1kai。
那么有 a n s = C ( a 1 n − 2 ) ∗ C ( a 2 n − 2 − a 1 ) ∗ . . . C ( a k n − 2 − a 1 − a 2 . . − a k − 1 ) = ( n − 2 ) ! ( n − 2 − s u m ) ! ∗ Π i = 1 k a i ! ∗ ( n − k ) ( n − 2 − s u m ) ans=C {a_1 \choose n-2}*C {a_2 \choose n-2-a_1}*...C {a_k \choose n-2-a_1-a_2..-a_{k-1}}=\frac{(n-2)!}{(n-2-sum)!*\Pi_{i=1} ^{k}a_i!}*(n-k)^{(n-2-sum)} ans=C(n−2a1)∗C(n−2−a1a2)∗...C(n−2−a1−a2..−ak−1ak)=(n−2−sum)!∗Πi=1kai!(n−2)!∗(n−k)(n−2−sum)
代码:
def quick_pow(a,b):
ans=1
while b>0:
if (b&1)>0 :
ans*=a
a*=a
b>>=1
return ans
def init(n):
fac = [0 for i in range(n + 1)]
fac[0]=1
for i in range(1,n+1):
fac[i]=fac[i-1]*i
return fac
if __name__ == '__main__':
# a,b=[int(i) for i in (input().split())]
# print(a,b)
# print(quick_pow(a,b))
n=int(input())
du=[]
for i in range(n):
x=int(input())
du.append(x)
if n==1:
if du[0]>0:
print(0)
else:
print(1)
exit()
sum=0
for i in du:
if i==0:
print(0)
exit()
if i==-1:
continue
sum+=i-1
if sum>n-2:
print(0)
exit()
#此时n>=2且du[]>1,且sum<=n-2
fac=init(n)
ans=fac[n-2]//fac[n-2-sum]
k=0
for i in du:
if i==-1:
continue
ans//=fac[i-1]
k+=1
ans*=quick_pow(n-k,n-2-sum)
print(int(ans))