P2624 [HNOI2008]明明的烦恼【prufer序列】
题意
给出标号为 \(1\) 到 \(N\) 的点,以及某些点最终的度数,如果对度数无要求则为 \(-1\),允许在任意两点间连线,可产生多少棵度数满足要求的树?
\(0 < N \leq 1000\)
分析
首先,令 \(k=\sum_{d_i\neq -1}{1},sum=\sum_{d_i\neq -1}{(d_i-1)}\),由于每棵树对应的 \(\text{prufer}\) 序列的长度为 \(n-2\),而已知度数要求的编号所占位置数为:\(sum\)。因此,对于有度数要求的编号的方案数为:
\[C_{n-2}^{sum}·\frac{sum!}{\prod_{d_i\neq -1}{(d_i-1)!}}
\]
对于序列剩下的 \(n-2-sum\) 个位置,每个位置有 \(n-k\) 个点可以选择。最终的方案总数为:
\[ans=C_{n-2}^{sum}·\frac{sum!}{\prod_{d_i\neq -1}{(d_i-1)!}}·(n-k)^{n-2-sum}
\]
由于数据比较大,所以使用 \(\text{python}\) 会简单。
代码
n = int(input())
d = [0 for i in range(0, n + 5)]
for i in range(1, n + 1):
d[i] = int(input())
k = 0
sum = 0
prod = 1
for i in range(1, n + 1):
if d[i] == 0:
print(0)
exit()
if d[i] != -1:
k += 1
sum += (d[i] - 1)
if sum > n - 2:
print(0)
exit()
f = [0 for i in range(0, n + 3)]
f[0] = 1
for i in range(1, n + 1):
f[i] = f[i - 1] * i
ans = f[n - 2] // f[n - 2 - sum] # sum写成了k
for i in range(1, n + 1):
if d[i] != -1:
ans //= f[d[i] - 1]
ans *= pow(n - k, n - 2 - sum)
print(int(ans))