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))

posted @ 2020-09-07 16:48  xzx9  阅读(148)  评论(0编辑  收藏  举报