CF1667E Centroid Probabilities

给定奇数 \(n\)。有一棵 \(n\) 个点的树,点 \(i\) 的父亲 \(p_i \in [1,i-1]\)。

对于所有 \(i \in [1,n]\),求出满足条件的所有树中,重心为点 \(i\) 的树的数量。

\(3 \leq n < 2 \times 10^5\)。


我们令 \(m = \dfrac{n+1}{2}\),则点 \(i\) 为重心的必要条件是 \(\text{size}_i \geq m\)。

我们不妨先求出 \(f_i\) 表示 \(\text{size}_i \geq m\) 的方案数。

我们不妨考虑枚举 \(\text{size}_i = j\),考虑如何计数。

首先,我们需要选择 \(j\) 个点作为子树,方案数 \(\dbinom{n-i}{j-1}\)。

这 \(j\) 个点构成一棵树,方案数为 \((j-1)!\)。

不在 \(i\) 子树内的点父节点只能在内部产生,方案数为 \((n-j-1)!\)。

\(i\) 的父亲有 \(i-1\) 种选法,即编号比 \(i\) 小的节点均可以选。

由上面的分析,可以得到:

\[f_i = \sum\limits_{j = m}^{n-i+1} \dbinom{n-i}{j-1}(j-1)!(n-j-1)!(i-1) \]

接下来对其化简:

\[\begin{aligned} & \sum\limits_{j = m}^{n-i+1} \dbinom{n-i}{j-1}(j-1)!(n-j-1)!(i-1) \\ = & \sum\limits_{j = m}^{n-i+1} \dfrac{(n-i)!(j-1)!(n-j-1)!(i-1)}{(j-1)!(n-i-j+1)!} \\ = & \sum\limits_{j = m}^{n-i+1} \dfrac{(n-i)!(n-j-1)!(i-1)}{(n-i-j+1)!} \\ = & (n-i)!(i-1) \sum\limits_{j = m}^{n-i+1} \dfrac{(n-j-1)!}{(n-i-j+1)!} \\ = & (n-i)!(i-1)(i-2)! \sum\limits_{j = m}^{n-i+1} \dfrac{(n-j-1)!}{(n-i-j+1)!(i-2)!} \\ = & (n-i)!(i-1)! \sum\limits_{j = m}^{n-i+1} \dbinom{n-j-1}{i-2} \\ = & (n-i)!(i-1)! \dbinom{n-m}{i-1} \\ = & \dfrac{(n-i)!(i-1)!(n-m)!}{(i-1)!(n-m-i+1)!} \\ = & \dfrac{(n-i)!(n-m)!}{(n-m-i+1)!} \end{aligned} \]

接下来考虑如何利用 \(f_i\) 求出答案 \(g_i\)。

在 \(\text{size}_i \geq m\) 的必要条件下,可能会发生重心在 \(i\) 子树内的情况。

进行容斥,对于 \(j \in [i+1,n]\),考虑 \(j\) 在 \(i\) 子树内的概率。

显然,顺着父亲往上跳,第一个到达的 \([1,i]\) 之间的节点是等概率随机的。

只有到达 \(i\),\(j\) 才能在 \(i\) 子树内。即 \(j\) 在 \(i\) 子树内概率为 \(\dfrac{1}{i}\)。

也就是说,\(g_i = f_i - \dfrac{\sum\limits_{j=i+1}^{n} g_j}{i}\)。

我们进行递推即可,时间复杂度 \(O(n)\),为了方便我写的是 \(O(n \log n)\)。

//Ad astra per aspera
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const long long mod=998244353;
long long f[200010],g[200010],fact[200010],inv_fact[200010];
long long inv(long long num){
	long long pre=mod-2,ans=1;
	while(pre){
		if(pre&1){
			ans=ans*num%mod;
		}
		num=num*num%mod;
		pre>>=1;
	}
	return ans;
}
int main(){
	int n;
	scanf("%d",&n);
	fact[0]=inv_fact[0]=1;
	for(int i=1;i<=n;i++){
		fact[i]=fact[i-1]*i%mod;
	}
	int m=(n+1)/2;
	for(int i=1;i<=n;i++){
		if(n-m>=i-1){
			f[i]=fact[n-i]*fact[n-m]%mod*inv(fact[n-m-i+1])%mod;
		}
	}
	long long sum=0;
	for(int i=n;i>=1;i--){
		g[i]=f[i]-sum*inv(i)%mod;
		g[i]=(g[i]%mod+mod)%mod;
		sum+=g[i];
		sum%=mod;
	}
	for(int i=1;i<=n;i++){
		printf("%lld ",g[i]);
	}
	return 0;
}
posted @ 2026-03-17 15:29  Oken喵~  阅读(29)  评论(0)    收藏  举报