Luogu3830 随机树

Arahc 11.0

题面

简化题意

一个初始情况只有根的二叉树,每次随机选一个叶子挂上一对左右儿子,直到叶子数为 nn。求所有叶子平均深度的期望和树高的期望。

n100n\leq 100

题解

第一问

fif_i 表示已经建了 ii 个叶子,所有叶子的深度平均值。则 ii 个叶子的树叶子深度之和为 fi×if_i\times i

考对于某个深度为 depidep_i 的点 ii,给它挂一对儿子会产生的影响。不难得到总的贡献为 depi+2dep_i+2。同时叶子数量多 。对于 i1i-1 个叶子,选到一个的概率是 1i1\frac{1}{i-1},所以有:

fi×i=fi1×(i1)+ji1depj+2i1=fi1×ifi1+ji1depji1+2(i1)i1\begin{aligned} f_i\times i &=f_{i-1}\times(i-1)+\sum_j^{i-1}\frac{dep_j+2}{i-1} \\ &=f_{i-1}\times i-f_{i-1}+\sum_j^{i-1}\frac{dep_j}{i-1}+\frac{2(i-1)}{i-1} \\ \end{aligned}

其中 ji1depji1\sum_j^{i-1}\frac{dep_j}{i-1}i1i-1 个叶子的平均深度,所以 ji1depii1=fi1\sum_j^{i-1}\frac{dep_i}{i-1}=f_{i-1}

fi×i=fi1×i+2f_i\times i=f_{i-1}\times i+2

得到 fi=fi1+2if_i=f_{i-1}+\frac{2}{i},初值 f1=0f_1=0O(n)\mathcal{O}(n) 递推即可。

第二问

fi,jf_{i,j} 表示有 ii 个叶子,树高为 jj,这样的树出现的概率:

Ans=i=1n1fn,i×iAns=\sum_{i=1}^{n-1} f_{n,i}\times i

枚举根节点的左子树内部的情况。设 pi,jp_{i,j} 表示一共有 ii 个叶子,其中 jj 个在根的左子树的概率。因为根节点的深度为 00,所以下图绿色部分的深度,等于两个红色部分深度的较大值加 11

pic-1

因此我们枚举左子树的子树,当这两边有一边的深度为 j1j-1 时,总的深度就是 jj。所以有:

fi,j=k=1i1pi,k×x=1jy=1jfk,x×fik,y[x=j1y=j1]f_{i,j}=\sum_{k=1}^{i-1}p_{i,k}\times\sum_{x=1}^{j}\sum_{y=1}^{j}f_{k,x}\times f_{i-k,y} [x=j-1 \lor y=j-1]

因为后面两个 sigma 的条件是 x,yx,y 有一个满足是 j1j-1,所以没必要套起来。时间复杂度 n4n^4

pi,jp_{i,j} 表示一共有 ii 个叶子,其中 jj 个在根的左子树的概率,fi,jf_{i,j} 表示有 ii 个叶子,且深度大于等于 jj 的概率。

考虑根的左儿子的两个子树的情况,只要有一边的深度大于等于 j1j-1,整个树的深度就大于等于 j1j-1。分别考虑左右子树是否有一边深度大于等于 j1j-1。注意两边都有可能大于等于 j1j-1,因此需要去除重复算的部分:

fi,j=k=1i1pi,k×(fk,j1+fik,j1fk,j1×fik,j1)f_{i,j}=\sum_{k=1}^{i-1}p_{i,k}\times(f_{k,j-1}+f_{i-k,j-1}-f_{k,j-1}\times f_{i-k,j-1})

pp 能预处理或 O(1)\mathcal O(1) 算,时间复杂度就是 n3n^3。考虑怎么算 pp

第一个 sigma 中枚举 kk 表示左子树的叶子个数。考虑左子树里有恰好 kk 个叶子的树如何生成。第一步是根挂叶子,然后左子树与右子树以某种顺序挂叶子,只要左子树挂了 k1k-1 次就够了。

顺序不影响叶子的个数,只要是 k1k-1 次左边和 ik1i-k-1 从右边组成的挂节点顺序就可以了。因此一个组合数 (i2k1)\binom{i-2}{k-1}

考虑左子树生成的方案数。kk 个叶子有 (k1)!(k-1)! 种方法。证明:设 kk 个叶子有 aka_k 种方法,而 kk 个叶子相当于 k1k-1 个叶子的情况任选叶子挂新节点,有 ak=ak1×(k1)a_k=a_{k-1}\times(k-1)

同理,右子树叶子数为 iki-k,生成的方案数为 (ik1)!(i-k-1)!。两种方法相乘,总共有 (k1)!(ik1)!(k-1)!(i-k-1)! 种方案。乘上前面求出的左右子树生成顺序的方案数 (i2)!(k1)!(ik1)!\frac{(i-2)!}{(k-1)!(i-k-1)!}。我们发现生成一个左子树有 kk 个叶子,右子树有 iki-k 个叶子的树的方案数为 (i2)!(i-2)!,与 kk 没有什么关系了。

回到 pp 的定义,pi,jp_{i,j} 表示一共有 ii 个叶子,其中 jj 个在根的左子树的概率。前面推出 pi,jp_{i,j}jj 无关。而左子树至少有一个叶子。因此左子树的叶子数有:1,2,3,,i11,2,3,\cdots,i-1 几种可能。因为是等概率的,所以有 pi,j=1i1p_{i,j}=\frac{1}{i-1}

fi,j=k=1i1fk,j1+fik,j1fk,j1×fik,j1i1f_{i,j}=\sum_{k=1}^{i-1}\frac{f_{k,j-1}+f_{i-k,j-1}-f_{k,j-1}\times f_{i-k,j-1}}{i-1}

初值 fi,0=1f_{i,0}=1。不难发现这样的递推是 n3n^3 的。考虑求答案。

nn 个叶子的树,深度不超过 n1n-1。因此设 gi,jg_{i,j} 表示有 ii 个叶子,深度等于 jj 的概率:

Ans=i=1n1gn,i×iAns=\sum_{i=1}^{n-1} g_{n,i}\times i

而且可以知道:

fi,j=k=jn1gi,kf_{i,j}=\sum_{k=j}^{n-1} g_{i,k}

因此对所有的 fn,jf_{n,j} 求和:

i=1n1fn,i=i=1n1j=in1gn,j=i=1n1gn,i×i=Ans\begin{aligned} \sum_{i=1}^{n-1} f_{n,i} &=\sum_{i=1}^{n-1}\sum_{j=i}^{n-1} g_{n,j} \\ &=\sum_{i=1}^{n-1} g_{n,i}\times i \\ &=Ans \end{aligned}

得出答案为 i=1n1fn,i\sum_{i=1}^{n-1} f_{n,i}

代码

采用 n3n^3 做法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include<bits/stdc++.h>
using namespace std;
const int max_n=303;
inline int read(){
int x=0;bool w=0;char c=getchar();
while(c<'0' || c>'9') w|=c=='-',c=getchar();
while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return w?-x:x;
}

int n,T;
double f1[max_n],f[max_n][max_n];

signed main(){
T=read()-1,n=read();
if(T){
for(register int i=0;i<=n;++i)
f[i][0]=1;
for(register int i=1;i<=n;++i)
for(register int j=1;j<=i-1;++j){
f[i][j]=0;
for(register int k=1;k<=i-1;++k)
f[i][j]+=f[k][j-1]+f[i-k][j-1]-f[k][j-1]*f[i-k][j-1];
f[i][j]/=i-1;
}
double ans=0.0;
for(register int i=1;i<=n-1;++i)
ans+=f[n][i];
printf("%.6lf",ans);
}
else{
f1[1]=0;
for(register int i=2;i<=n;++i)
f1[i]=f1[i-1]+2.0/i;
printf("%.6lf",f1[n]);
}
return 0;
}
  • 标题: Luogu3830 随机树
  • 作者: Arahc
  • 创建于 : 2021-10-28 08:00:00
  • 更新于 : 2023-03-18 08:20:48
  • 链接: https://arahc.github.io/2021/10/28/【题解】Luogu3830-随机树/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
Luogu3830 随机树