ARC106F Figures / A.圣诞树 题解(Prufer 序列的应用)

\(n\) 个点,第 \(i\) 个点上有 \(a_i\) 个可区分的洞,问在这些洞之间连 \(n-1\) 条线使得形成一棵树的方案数。对给定的模数 \(m\) 取模。

\(n\le 10^6,a_i\le m\)

这个题有点厉害。

我这个解法需要用到 prufer 序列的一个结论。首先 prufer 序列是一个将 \(n\) 个点的带标号无根树与长度为 \(n-2\),值域为 \(1\sim n\) 的整数序列一一对应的一种构造方案。具体构造方案如下:

进行以下操作直到只剩下两个点:

  1. 拿出所有叶子中编号最小的点 \(x\)
  2. \(x\) 相邻的唯一一个点加入 prufer 序列。
  3. \(x\) 从这棵树里删除。

因为最后只剩下两个点,所以这个序列长度为 \(n-2\)

这个序列就被我们称为 prufer 序列。prufer 序列有非常多良好的性质。

首先,根据上述构造过程,我们可以知道一个度数为 \(d_x\) 的点 \(x\) 在 prufer 序列中恰好出现了 \(x-1\) 次,因为只有恰好一次删除与 \(x\) 相邻的边时,没有在 prufer 序列里记录 \(x\)。因此所有没出现过的点就是叶子节点。

其次,prufer 序列和有标号无根树是一一对应的关系,因为你可以这么根据 prufer 序列还原一棵树:

拿出所有没有在 prufer 序列中出现的点,这个集合记为 \(S\)

重复以下操作直到 prufer 序列为空:

  1. 令当前 \(S\) 集合中编号最小的点为 \(x\),prufer 序列的第一个元素为 \(y\)
  2. 在树中添加一条边 \((x,y)\)。从 \(S\) 中删去 \(x\),删除 prufer 序列的第一个元素。
  3. 如果 \(y\) 在 prufer 序列中不再出现(即现在 \(y\) 也是一个叶子节点了),则将 \(y\) 加入到集合 \(S\)

在进行了 \(n-2\) 次上述操作后,集合 \(S\) 中应该恰有两个点,再在这两个点之间连边即可。

根据以上构造过程,我们就证明了一个 prufer 序列也只能恰好被还原为一个带标号无根树。因此 prufer 序列和无根树是双射关系。

那么接下来,如果给定了一个度数序列 \(d_1,d_2,\cdots d_n\),即代表 \(i\) 的度数是 \(d_i\),如何求有多少个无根树满足这个度数序列呢?这个时候就要用到 prufer 序列的性质,即度数为 \(i\) 的点出现了 \(d_i-1\) 次,那么也就是,任意一个满足 \(i\) 出现了 \(d_i-1\) 次的 prufer 序列就对应了一个满足条件的无根树。这个无根树一共有多少个呢?显然是 \(\dfrac{(n-2)!}{\prod_{i=1}^n(d_i-1)!}\) 个。

回到我们的问题来。我们可以先枚举一个度数序列 \(d_i\),答案即为

\[\sum_{d_1+d_2+\cdots+d_n=2n-2}\frac{(n-2)!}{\prod (d_i-1)!}\prod_{i=1}^na_i^{\underline{d_i}} \]

其中 \(a_i^{\underline{d_i}}\) 代表 \(a_i\)\(d_i\) 次下降幂,也就是 \(a_i\times (a_i-1)\times\cdots\times(a_i-d_i+1)\)

不妨令新的 \(d_i\) 等于原来的 \(d_i-1\),这样看着好看一点。式子转为:

\[\sum_{d_1+d_2+\cdots+d_n=n-2}\frac{(n-2)!}{\prod d_i!}\prod_{i=1}^na_i^{\underline{d_i+1}} \]

由于两个 \(\prod\)\(i\) 上下界都一样,我们不妨直接把 \(d_i!\) 放进后面的 \(\prod\) 里,这一步是为了把 \((n-2)!\) 提到求和式外边,方便以后化简:

\[(n-2)!\sum_{d_1+d_2+\cdots+d_n=n-2}\prod_{i=1}^n\frac{a_i^{\underline{d_i+1}}}{d_i!} \]

后面这个 \(\dfrac{a_i^{\underline{d_i+1}}}{d_i!}\) 我们想把它转换成一个组合数的形式,因为上面是一段下降幂连乘,下面是一个除以一个阶乘。发现问题在于上方分子多了一个 \(a_i\),我们直接把这个 \(a_i\) 也提到外边:

\[(n-2)!\prod a_i(\sum_{d_1+d_2+\cdots+d_n=n-2}\prod_{i=1}^n\frac{(a_i- 1)^{\underline{d_i}}}{d_i!})\\ =(n-2)!\prod a_i(\sum_{d_1+d_2+\cdots+d_n=n-2}\prod_{i=1}^n\binom{a_i-1}{d_i}) \]

然后回忆一下范德蒙德卷积,范德蒙德卷积是在说这么一个事:如果你要从 \(n\) 个男生 \(m\) 个女生中选出 \(k\) 个人,方案数是 \(\binom{n+m}{k}\)。但是你也可以这么想,你枚举你选了多少个男生,设为 \(i\),那也就是你要选 \(k-i\) 个女生,也就是 \(\sum_{i=1}^k\binom{n}{i}\binom{m}{k-i}\)。这两个式子的组合意义是相同的,也就是有恒等式:

\[\binom{n+m}{k}=\sum_{i=1}^k\binom{n}{i}\binom{m}{k-i} \]

同理,我们不妨扩展一下这个式子,有 \(p\) 元形式的恒等式:

\[\binom{a_1+a_2+\cdots+a_p}{m}=\sum_{i_1+i_2+\cdots+i_p=m}\binom{a_1}{i_1}\binom{a_2}{i_2}\cdots\binom{a_p}{i_p} \]

重新观察我们上面这个答案式子,发现后面这一项其实就是要你在 \(\sum (a_i-1)=\sum a_i-n\) 项里面选 \(n-2\) 项,因此化简为:

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

\((n-2)!\) 乘进这个组合数里面(避免算逆元,因为 \(m\) 不一定是质数),得到:

\[ans=\prod_{i=1}^n a_i(\sum_{i=1}^n a_i-n)^{\underline{n-2}} \]

直接算即可。

void work() {
	int n, mod; cin >> n >> mod;
	vector<int> a(n + 1);
	for (int i = 1; i <= n; ++i)
		cin >> a[i];
	int prod = 1, sum = 0;
	for (int i = 1; i <= n; ++i) {
		prod = prod * a[i] % mod;
		sum = (sum + a[i]) % mod;
	}
	sum = ((sum - n) % mod + mod) % mod;
	int ans = prod;
	for (int i = 0; i < n - 2; ++i) {
		ans = (ans * (sum - i + mod) % mod) % mod;
	}
	cout << ans << endl;
}
posted @ 2025-11-20 17:33  小蛐蛐awa  阅读(1)  评论(0)    收藏  举报