prufer 相关

主要是数数。

prufer 序列是一种将带标号无根树用一个唯一的整数序列表示的
方法。

prufer 序列可以将一个带标号的 \(n\) 个结点的无根树用 \(n − 2\)\([1, n]\) 中的整数表示,也可以用 \(n − 2\)\([1, n]\) 中的整数还原出原树。

每次选择叶结点中编号最小的一个并删掉它,第 i 次操作后在序列的第 \(i\) 位记录下它连接到的结点的编号。显然由于树一定有叶子,所以该操作一定能够进行 \(n − 2\) 次,得到的序列就是 prufer 序列,这与无根树意义对应。

  • \(n\) 个点有编号无根树数量 \(n^{n-2}\)

  • \(n\) 个点,每个点度数为 \(d_i\),方案数是 \(\binom{n-2}{d_1-1,d_2-1,...,d_n-1}\),因为第 \(i\) 个点会在 prufer 序列中出现 \(d_i-1\) 次。

  • \(n\) 个点分成 \(k\) 个连通块,把它们联通的方案数:\(n^{k-2}\prod s_i\)\(s_i\) 表示连通块大小。CF156D

考虑每次删去一个连通块,记录 prufer 序列,这样贡献是 \(n^{k-2}\),再考虑删去这个连通块时哪个点与父亲连边,贡献是 \(\prod s_i\)

  • \(n\) 个点的完全 \(k\) 分图的方案数是 \(n^{k-2}\prod (n-s_i)^{s_i-1}\)

不会。

ARC106F

首先考虑形成树的方案,那么考虑 prufer 序列,也就是考虑每个点在树上的度数,假设度数为 \(d_i\),那么形成树的方案数是 \(\frac{(n-2)!}{\prod (d_i-1)!}\)

可以轻松地把式子写出来。

\[\sum_{\sum d_i=2n-2} \frac{(n-2)!}{\prod (d_i-1)!} \prod \frac{a_i!}{(a_i-d_i)!} \]

合并成组合数。

\[(n-2)!\sum_{\sum d_i=2n-2} \prod \frac{\binom{a_i}{d_i}}{d_i} \]

发现这个除 \(d_i\) 不好搞,乘上去。

\[(n-2)!\sum_{\sum d_i=2n-2} \prod a_i \binom{a_i-1}{d_i-1} \]

\[=(n-2)!\prod a_i\sum_{\sum d_i=2n-2} \prod \binom{a_i-1}{d_i-1} \]

最后上个生成函数即可。

\[=(n-2)!\prod a_i [x^{n-2}] \prod \binom{a_i-1}{d_i}x^{d_i} \]

\[=(n-2)!\prod a_i [x^{n-2}] \prod (1+x)^{a_i-1} \]

\[=(n-2)!\prod a_i \binom{\sum a_i - n}{n-2} \]

sxyzP1086

先直接枚举每个点度数 \(d_i\),写出式子。

\[=\sum_{\sum d_i=2n-2} \binom{n-2}{d_1-1,d_2-1,...,d_n-1} \prod_{i=1}^n d_iw_i^{d_i}\\ = (n-2)!\sum_{\sum d_i=2n-2}\prod_{i=1}^n \frac{d_iw_i^{d_i}}{(d_i-1)!}\\ =(n-2)![x^{n-2}] \prod_{i=1}^n \sum_{j=0}^{\infty} \frac{(j+1)w_i^{j+1}x^j}{j!}\\ =(n-2)![x^{n-2}] \prod_{i=1}^n w_i \sum_{j=0}^{\infty} (\frac{w_i^j}{j!}+\frac{w_i^j}{(j-1)!})x^j\\ = (n-2)![x^{n-2}] \prod_{i=1}^n w_i(1+w_ix)e^{w_ix}\\ = (n-2)!\prod_{i=1}^n w_i [x^{n-2}]e^{(\sum w_i)x}\prod_{i=1}^n (1+w_ix) \\ \]

后面那个部分用背包或者分治 FFT,然后去前面找对应的 \(e^{(\sum w_i)x}\) 展开项,但是注意此时会去除以一个 \(i!\),那么和前面的 \(n!\) 抵掉,就是一个后缀和。

复杂度 \(O(n^2)\) 或者 \(O(n\log^2 n)\)


另一个解决有标号树数数问题的方法:

先考虑最原始的无根树问题,我们把他先变成有根树,然后去确定每一个点的父亲,这样就能不重复地得到树了。

考虑一条一条加边,先枚举一个节点,然后找一个点作为它的儿子,这个儿子不能和它在一个联通块内,那么可以得到总方案数就是 \(\prod_{i=1}^{n-1} n(n-i)=n^{n-1}(n-1)!\)

然后可以发现除根外每个点都要选一个父亲,这是无序的,但在上面的计算中是有序的,所以除掉,得到 \(n^{n-1}\)

把树变成无根树,那么少乘一个 \(n\) 即可,得到和 prufer 一样的答案:\(n^{n-2}\)

类似的,我们可以得到 \(n\) 个点, \(k\) 条边的有根森林的数量是 \(\frac{1}{k!}\sum_{i=1}^k n(n-i)=n^k\frac{(n-1)!}{(n-k-1)!k!}=n^k\binom{n-1}{k}\)

这个东西也可以用 prufer 理解,考虑建一个虚点 \(0\) 连向所有的根,那么 prufer 序列长度为 \(n-1\),其中有 \(k\) 个位置不为 \(0\),也可以得到上面的式子。

这个做法的好处是,把树变成了有根树,能更好地处理一些与边相关的题目。

ARC155 *? \(\color{Gold}\bigstar\)

先变成有根树,这样所有边分成两类:指向根和指向儿子。

指向根的点,每个点最多一条,先直接枚举一个集合 \(S\) 表示这里面的点都有指向父亲的边。

考虑指向父亲的这个方案数,如果选出的点的 \(d_i\) 都不为 \(0\),那么容易发现这个方案数只和集合大小 \(|S|\) 有关,也就是所有 \(|S|\) 相等的方案数相同,那么这些 \(S\) 的总方案数就是上面那个问题连 \(|S|\) 条边的方案数。因此一个集合的方案数就是

\[n^{|S|}\binom{n-1}{|S|}\frac{1}{\binom{n}{|S|}}=n^{|S|-1}(n-|S|) \]

然后考虑剩下的都是父亲指向儿子的边,那么考虑类似拓扑排序,每次找一个度数为 \(0\) 的点去找一个父亲,这样一定可以一直进行下去。

但是我们并不知道有多少个点还有度数,但是我们知道剩余的总度数。

对于每一个点的出边,对其进行编号,即所有边都不同,这样相当于答案要除以 \(\prod d_i!\)

那么只需要找一条边去连即可,那么贡献就变成了 \((n-|S|-1)!\)

然后上面连父亲的方案数也会变化,需要乘以 \(\prod d_i\),因为在所有出边里选一条。

最后的式子是:

\[f_{S}=n^{|S|-1}(n-|S|)!\prod_{i\in S} d_i \]

这个东西要求和,可以发现前两项都只和 \(|S|\) 有关,后面又是一个简单的生成函数,枚举 \(|S|\),得到:

\[\sum_{i=0}^n n^{i-1}(n-i)![x^i]\prod_{j=1}^n (1+d_ix) \]

分治 NTT 即可,复杂度 \(O(n\log^2 n)\)

code

posted @ 2023-01-31 19:40  houzhiyuan  阅读(60)  评论(0编辑  收藏  举报