题目:BZOJ2830.
题目大意:一棵有
n
n
n个叶子的二叉树可以通过
n
−
1
n-1
n−1次等概率随机往一个叶节点上加两个儿子生成.现在给定
q
,
n
q,n
q,n,当
q
=
1
q=1
q=1时输出
n
n
n个叶子的二叉树叶子深度平均值的期望,
q
=
2
q=2
q=2输出树高的期望,注意根节点深度为
0
0
0.
1
≤
q
≤
2
,
1
≤
n
≤
100
1\leq q\leq 2,1\leq n\leq100
1≤q≤2,1≤n≤100.
考虑
q
=
1
q=1
q=1,很容易想到设
f
[
i
]
f[i]
f[i]表示
i
i
i个叶子的答案,方程:
f
[
i
]
=
f
[
i
−
1
]
∗
(
i
−
1
)
+
f
[
i
−
1
]
+
2
i
=
f
[
i
−
1
]
+
i
2
f[i]=\frac{f[i-1]*(i-1)+f[i-1]+2}{i}=f[i-1]+\frac{i}{2}
f[i]=if[i−1]∗(i−1)+f[i−1]+2=f[i−1]+2i
考虑
q
=
2
q=2
q=2,发现只设一维状态不行了,考虑加一维状态,设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示
i
i
i个叶子深度为
j
j
j的概率.通过枚举左子树的叶子数,我们可以列出如下方程:
f
[
i
]
[
j
]
=
∑
k
=
1
i
−
1
p
[
i
]
[
j
]
(
f
[
k
]
[
j
−
1
]
∑
t
=
0
j
f
[
i
−
k
]
[
t
−
1
]
+
f
[
i
−
k
]
[
j
−
1
]
∑
t
=
0
j
f
[
k
]
[
t
]
−
f
[
k
]
[
t
]
∗
f
[
i
−
k
]
[
t
]
)
f[i][j]=\sum_{k=1}^{i-1}p[i][j](f[k][j-1]\sum_{t=0}^{j}f[i-k][t-1]+f[i-k][j-1]\sum_{t=0}^{j}f[k][t]-f[k][t]*f[i-k][t])
f[i][j]=k=1∑i−1p[i][j](f[k][j−1]t=0∑jf[i−k][t−1]+f[i−k][j−1]t=0∑jf[k][t]−f[k][t]∗f[i−k][t])
其中 p [ i ] [ j ] p[i][j] p[i][j]表示 i i i个叶子的树 j j j个在左子树的概率.
我们发现只要能够预处理出 p [ i ] [ j ] p[i][j] p[i][j]就可以 O ( n 4 ) O(n^4) O(n4)解决这个问题了,可是这个不够快.
考虑这两个式子中都有一个和的形式,可以考虑前缀和,但是由于计算答案的式子:
E
(
X
)
=
∑
i
=
1
n
f
[
n
]
[
i
]
∗
i
E(X)=\sum_{i=1}^{n}f[n][i]*i
E(X)=i=1∑nf[n][i]∗i
用前缀和来处理这个式子有些麻烦,所以考虑变成后缀和,即
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示
i
i
i个叶子深度至少为
j
j
j的概率,那么:
E
(
X
)
=
∑
i
=
1
n
f
[
n
]
[
i
]
f
[
i
]
[
j
]
=
∑
k
=
1
i
−
1
p
[
i
]
[
j
]
(
f
[
k
]
[
j
−
1
]
+
f
[
i
−
k
]
[
j
−
1
]
−
f
[
k
]
[
j
−
1
]
∗
f
[
i
−
k
]
[
j
−
1
]
)
E(X)=\sum_{i=1}^{n}f[n][i]\\ f[i][j]=\sum_{k=1}^{i-1}p[i][j](f[k][j-1]+f[i-k][j-1]-f[k][j-1]*f[i-k][j-1])
E(X)=i=1∑nf[n][i]f[i][j]=k=1∑i−1p[i][j](f[k][j−1]+f[i−k][j−1]−f[k][j−1]∗f[i−k][j−1])
这个时候计算的复杂度就变成 O ( n 3 ) O(n^3) O(n3)的了,但是我们还不知道 p [ i ] [ j ] p[i][j] p[i][j]呢.
其实
p
[
i
]
[
j
]
=
1
i
−
1
p[i][j]=\frac{1}{i-1}
p[i][j]=i−11,这个东西用数学归纳法证明:
p
[
i
]
[
j
]
=
p
[
i
−
1
]
[
j
−
1
]
∗
j
−
1
i
−
1
+
p
[
i
−
1
]
[
j
]
∗
i
−
1
−
j
i
−
1
p[i][j]=p[i-1][j-1]*\frac{j-1}{i-1}+p[i-1][j]*\frac{i-1-j}{i-1}
p[i][j]=p[i−1][j−1]∗i−1j−1+p[i−1][j]∗i−1i−1−j
若
p
[
i
−
1
]
[
j
]
=
1
i
−
2
p[i-1][j]=\frac{1}{i-2}
p[i−1][j]=i−21,那么:
p
[
i
]
[
j
]
=
1
i
−
2
(
j
−
1
i
−
1
+
i
−
1
−
j
i
−
1
)
=
1
i
−
1
p[i][j]=\frac{1}{i-2}(\frac{j-1}{i-1}+\frac{i-1-j}{i-1})=\frac{1}{i-1}
p[i][j]=i−21(i−1j−1+i−1i−1−j)=i−11
那么代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100;
int n,q;
double f1[N+9],f2[N+9][N+9],ans;
Abigail into(){
scanf("%d%d",&q,&n);
}
Abigail work1(){
f1[1]=0;
for (int i=2;i<=n;++i)
f1[i]=f1[i-1]+2.0/i;
ans=f1[n];
}
Abigail work2(){
for (int i=1;i<=n;++i) f2[i][0]=1;
for (int i=2;i<=n;++i)
for (int j=1;j<i;++j){
for (int k=1;k<i;++k)
f2[i][j]+=f2[k][j-1]+f2[i-k][j-1]-f2[k][j-1]*f2[i-k][j-1];
f2[i][j]/=i-1;
}
for (int i=1;i<n;++i)
ans+=f2[n][i];
}
Abigail outo(){
printf("%.6lf\n",ans);
}
int main(){
into();
q==1?work1():work2();
outo();
return 0;
}