1 条题解
-
0
自动搬运
来自洛谷,原作者为

TheLostWeak
**搬运于
2025-08-24 21:36:00,当前版本为作者最后更新于2019-03-24 23:13:19,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
大致题意: 给定每个点的度数,让你求有多少种符合条件的无根树。
前言:序列
简介
序列应该是一个比较实用的东西。
据大佬说,一切与度数有关的树上计数问题,都可以用它以及它的性质来解决。
而听说最近特别喜欢出计数题,所以有必要学一学。
转化:从无根树到序列
现在,给你一棵树,我们要考虑如何把它变成序列。

我们需要重复进行以下操作,直至树中只剩下两个点:
- 找到一个度数为,且编号最小的点。(其中编号最小保证了后面将会提到的序列的唯一对应性,同时也方便从序列转化回无根树)
- 把这个点的父亲节点加入序列,然后把这个点从树中删除。
然后我们就得到了一个长度为的序列,这就是序列。
所以它有什么实际意义呢?
我也不知道。以上面的图为例,我们可以模拟这一过程如下:
- 找到号节点,将其父结点加入序列,然后将其删去。此时序列:。
- 找到号节点,将其父结点加入序列,然后将其删去。此时序列:。
- 找到号节点,将其父结点加入序列,然后将其删去。此时序列:。
- 找到号节点,将其父结点加入序列,然后将其删去。此时序列:。
- 找到号节点,将其父结点加入序列,然后将其删去。此时序列:。
所以,最后得到的序列就是。
转化:从序列到无根树
还是以刚才那棵树为例吧,我们要考虑如何把它的序列变回它本身。
我们需要重复进行以下操作,直至点集中只剩下两个点:(初始化所有点都在点集中)
- 取出序列最前面的元素。
- 取出在点集中的、且当前不在序列中的最小元素。(这恰好呼应了前面提到过的选取编号最小的节点)
- 在之间连接一条边。(注意前面的取出相当于删除)
最后,我们在点集中剩下的两个点中连一条边。
显然这有条边,且绝对不会形成环,因此它是一棵树,且就是原树。
以上面的序列为例,我们可以模拟这一过程如下:
- 取出连边。此时序列:,点集:。
- 取出连边。此时序列:,点集:。
- 取出连边。此时序列:,点集:。
- 取出连边。此时序列:,点集:。
- 取出连边。此时序列:,点集:。
最后再在间连边,就可以得到原树了。
序列的性质及相关结论
讲了这么多,我们最关键的还是序列的一些性质,以及与其有关的一些结论。(
毕竟前面也提到过,我也不知道这东西有什么实际意义)-
重要性质:序列与无根树一一对应。
这应该显然吧,通过前面的介绍应该可以直接得出。
而由这个性质,我们才能推导出后面的结论。
-
度数为的节点会在序列中出现次。
当某个节点度数为时,会直接被删掉,否则每少掉一个相邻的节点,它就会在序列中出现次。
因此共出现次。
-
一个个节点的完全图的生成树个数为。
对于一个个点的无根树,它的序列长为,而每个位置有种可能性,因此可能的序列有种。
又由于序列与无根树一一对应,因此生成树个数应与序列种树相同,即。
-
对于给定度数为的一棵无根树共有种情况。
由上面的性质可以知道,度数为的节点会在序列中出现次。
则就是要求出个的全排列个数。
而上面那个式子就是可重全排列公式。(即全排列个数除以重复元素内部的全排列个数)
大致就是这些。
解法
现在回到这道题,这显然是一道利用序列求解的裸题。
考虑到由序列得到的结论:对于给定度数为的一棵无根树共有种情况。
套公式即可。
高精/质因数分解/
等等,答案小于?
这看似在范围内,但是我们前面有除法啊!运算过程中肯定会爆!
然后就有种做法:
- 高精。
- 质因数分解。即把每个质因数出现的次数记下来,然后除法就变成了减法。最后相乘即可。
- !
自带高精,写这种题目的必备利器。
我自然是选择了。
最后提醒一句,需要判无解!
代码
n=(int)(input())#读入n if n==1:#特判n=1的情况 x=(int)(input());#读入唯一的节点度数 if x==0:print(1);#如果这个节点度数为0,说明只有一种解法 else:print(0);#否则,无解 exit();#退出程序 f=[0 for i in range(n+5)];f[0]=1;#建立阶乘数组 for i in range(1,n+1):f[i]=f[i-1]*i;#预处理阶乘 ans=f[n-2];tot=0;s=input().split();#初始化ans为(n-2)!,用tot统计度数和来判断是否无解 for i in range(n): x=(int)(s[i]); if x==0:print(0);exit();#如果存在某个点度数为0,说明图不连通,输出0 tot+=x-1;ans//=f[x-1];#统计度数和,更新答案 if(tot==n-2):print(ans);#如果度数和为n-2,输出ans else:print(0);#否则无解
- 1
信息
- ID
- 1286
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者