题面
SOL
分两个问题讨论;
Q1 :显然的期望dp定义式 :
f
[
i
]
:
第
i
步
的
期
望
平
均
叶
子
深
度
f[i]:第i步的期望平均叶子深度
f[i]:第i步的期望平均叶子深度,
转移方程:
f
[
i
]
=
f
[
i
−
1
]
∗
(
i
−
1
)
+
f
[
i
−
1
]
+
2
i
,
−
>
f
[
i
]
=
f
[
i
−
1
]
+
2
i
.
{f[i]={f[i-1]*(i-1)+f[i-1]+2}\over{i}},->f[i]=f[i-1]+{2\over i}.
if[i]=f[i−1]∗(i−1)+f[i−1]+2,−>f[i]=f[i−1]+i2.
可以再数学化简,这里没必要了。
Q2: 上一问好做,是因为我们可以直接从任意一个点转移。这一问要求最大深度的期望,如果要这样做,还要维护一个最大深度对应的叶子数。留作讨论吧。 。(updated, 9.23 ,这样定义状态包含了条件本身的概率,而子问题的条件和当前的条件不一样,不知道条件之间的转移概率,所以这个方法不行。)
从"拼树"的角度思考,一颗树由 一个根节点加左右两个子树拼接而成,左右子树是原问题的子问题,于是我们定义 f [ i ] [ j ] 表 示 有 i 个 叶 子 节 点 的 树 , 深 度 为 j 的 概 率 f[i][j]表示有i个叶子节点的树,深度为j的概率 f[i][j]表示有i个叶子节点的树,深度为j的概率,
那么枚举左右两子树,加上当前根节点就可以直接转移了。(注意本题特殊性,还要乘以生成左右子树叶节点树对应的概率)
法一:
f
[
i
]
[
j
]
=
∑
L
=
1
i
−
1
p
[
i
]
[
L
]
∗
(
∑
k
=
1
j
−
1
f
[
L
]
[
j
−
1
]
∗
f
[
i
−
L
]
[
k
]
+
∑
k
=
1
j
−
1
f
[
L
]
[
k
]
∗
f
[
i
−
L
]
[
j
−
1
]
−
f
[
L
]
[
j
−
1
]
∗
f
[
i
−
L
]
[
j
−
1
]
)
f[i][j]=\sum_{L=1}^{i-1}p[i][L]*(\sum_{k=1}^{j-1}f[L][j-1]*f[i-L][k]+\sum_{k=1}^{j-1}f[L][k]*f[i-L][j-1]-f[L][j-1]*f[i-L][j-1])
f[i][j]=L=1∑i−1p[i][L]∗(k=1∑j−1f[L][j−1]∗f[i−L][k]+k=1∑j−1f[L][k]∗f[i−L][j−1]−f[L][j−1]∗f[i−L][j−1])
p
[
i
]
[
j
]
=
p
[
i
−
1
]
[
j
−
1
]
∗
j
−
1
i
−
1
+
p
[
i
−
]
[
j
]
∗
(
1
−
j
i
−
1
)
p[i][j]=p[i-1][j-1]*{{j-1}\over{i-1}}+p[i-][j]*(1-{j\over{i-1}})
p[i][j]=p[i−1][j−1]∗i−1j−1+p[i−][j]∗(1−i−1j)
这里
f
f
f数组可以前缀和转移优化,
O
(
n
3
)
O(n^3)
O(n3)统计答案:
a
n
s
=
∑
j
=
1
n
−
1
f
[
n
]
[
j
]
∗
j
.
ans = \sum_{j=1}^{n-1}f[n][j]*j.
ans=∑j=1n−1f[n][j]∗j.
法二
使用全期望公式:
f
[
i
]
[
j
]
:
i
个
叶
节
点
的
子
树
,
深
度
大
于
等
于
j
的
概
率
f[i][j]:i个叶节点的子树,深度大于等于j的概率
f[i][j]:i个叶节点的子树,深度大于等于j的概率,
a
n
s
=
∑
i
=
1
n
−
1
f
[
n
]
[
i
]
ans=\sum_{i=1}^{n-1}f[n][i]
ans=∑i=1n−1f[n][i].
转移有:
f
[
i
]
[
j
]
=
∑
L
=
1
i
−
1
p
[
i
]
[
L
]
∗
(
f
[
L
]
[
j
−
1
]
+
f
[
i
−
L
]
[
j
−
1
]
−
f
[
L
]
[
j
−
1
]
∗
f
[
i
−
L
]
[
j
−
1
]
)
f[i][j]=\sum_{L=1}^{i-1}p[i][L]*(f[L][j-1]+f[i-L][j-1]-f[L][j-1]*f[i-L][j-1])
f[i][j]=L=1∑i−1p[i][L]∗(f[L][j−1]+f[i−L][j−1]−f[L][j−1]∗f[i−L][j−1])
一样 O(n^3)解决 (左右子树都大于等于
j
−
1
j-1
j−1的概率被算了两次,减掉即可)
PS
p
[
i
]
[
k
=
1...
i
−
1
]
p[i][k=1...i-1]
p[i][k=1...i−1] 其实就等于
1
i
−
1
{1\over{i-1}}
i−11。
证明:
先选左右子树,生成选法序列,再在子树里选叶节点,生成选树数列。
对于
p
[
i
]
[
j
]
p[i][j]
p[i][j],
从1个叶子节点开始构造,每次选L,L增加一个,选R,R增加一个;
总共选了 k 个 L ,选的方案是
(
i
−
2
k
)
{i-2}\choose k
(ki−2),为
(
i
−
2
)
!
(
i
−
2
−
k
)
!
∗
k
!
{{(i-2)!}\over{(i-2-k)! * k!}}
(i−2−k)!∗k!(i−2)!.
对于子树的拼接方案,左子树叶节点从1 到
k
k
k,总共
k
!
k!
k!总生成方法。同理,右子树总共
(
i
−
2
−
k
)
!
(i-2-k)!
(i−2−k)!种生成方法。
所以总的选法是序列生成方案*子树生成方案,为
(
i
−
2
)
!
(
i
−
2
−
k
)
!
∗
k
!
∗
k
!
∗
(
i
−
2
−
k
)
!
=
(
i
−
2
)
!
{{(i-2)!}\over{(i-2-k)! * k!}}*k!*(i-2-k)!=(i-2)!
(i−2−k)!∗k!(i−2)!∗k!∗(i−2−k)!=(i−2)!
所以总方案数和左右儿子个数无关,
p
[
i
]
[
j
]
=
1
i
−
1
p[i][j]={1\over{i-1}}
p[i][j]=i−11.
证毕。
CODE
#include<bits/stdc++.h>
#define pf printf
#define sf scanf
#define cs const
#define ll long long
#define db double
#define ri register int
using namespace std;
cs int N=110;
db p[N][N],f[N][N],g[N];
int n;
inline void init_p(){
p[2][1]=1;
for(ri i=3;i<=n;++i){
for(ri j=1;j<i;++j){
p[i][j]=p[i-1][j-1]*(j-1)/(1.0*(i-1))+p[i-1][j]*(1.0-1.0*j/(1.0*(i-1)));
}
}
}
inline void init_f(){
f[1][0]=1;
for(ri i=2;i<=n;++i){
f[i][1]=1;
for(ri j=2;j<i;++j){
for(ri k=1;k<i;++k){
f[i][j]+=p[i][k]*(f[k][j-1]+f[i-k][j-1]-f[k][j-1]*f[i-k][j-1]);
}
}
}
db ans=0;
for(ri i=1;i<n;++i)ans+=f[n][i];
printf("%.6lf",ans);
}
inline void init_g(){
g[1]=0;
for(ri i=2;i<=n;++i)g[i]=g[i-1]+2.0/(1.0*i);
printf("%.6lf",g[n]);
}
signed main (){
int q;sf("%d%d",&q,&n);
if(q==1)init_g();
if(q==2)init_p(),init_f();
return 0;
}