概率 / 期望 dp 基础题。
有一个二叉树的背景。
这题有两个值得学习的 trick 。
先看第一问。假设有 i − 1 i-1 i−1 个叶子结点,每个节点的平均深度为 f i − 1 f_{i-1} fi−1 。
然后随机选一个节点复制。这个节点的期望深度为 f i − 1 f_{i-1} fi−1
于是 f i = ( i − 1 ) f i − 1 + f i − 1 + 2 i = f i − 1 + 2 i f_{i}=\frac{(i-1)f_{i-1}+f_{i-1}+2}{i}=f_{i-1}+\frac{2}{i} fi=i(i−1)fi−1+fi−1+2=fi−1+i2
再来看第二问。
设 g [ i ] [ j ] g[i][j] g[i][j] 表示 i i i 次扩展,最终树的深度 ≥ j \geq j ≥j 的 概率 。
那么树的期望深度 ∑ i = 1 n − 1 g [ n − 1 ] [ i ] \sum_{i=1}^{n-1}g[n-1][i] ∑i=1n−1g[n−1][i]
观察到总方案数为 ( i − 1 ) ! (i-1)! (i−1)! ,如果左子树进行 k k k 次 ,右子树进行 i − k − 1 i-k-1 i−k−1 次 ,那么 p = k ! ( i − k − 1 ) ! ( i − 1 k ) i ! = 1 i p=\frac{k!(i-k-1)!\binom{i-1}{k}}{i!}=\frac{1}{i} p=i!k!(i−k−1)!(ki−1)=i1 。
那么根据概率 / 期望公式, g [ i ] [ j ] = ∑ k = 0 i − 1 g [ k ] [ j ] + g [ i − k − 1 ] [ j ] − g [ k ] [ j ] ∗ g [ i − k − 1 ] [ j ] i g[i][j]=\frac{\sum_{k=0}^{i-1}g[k][j]+g[i-k-1][j]-g[k][j]*g[i-k-1][j]}{i} g[i][j]=i∑k=0i−1g[k][j]+g[i−k−1][j]−g[k][j]∗g[i−k−1][j]
时间复杂度 O ( n 3 ) O(n^3) O(n3) 。
#include<bits/stdc++.h>
#define db double
using namespace std;
const int N=105;
db dp[N],dp2[N][N];
int n,Q;
int main() {
for(int i=1;i<=100;i++) {
dp[i]=dp[i-1]+2.0/(i+1);
}
for(int i=0;i<=100;i++) dp2[i][0]=1;
for(int i=1;i<=100;i++) {
for(int j=1;j<=i;j++) {
for(int k=0;k<i;k++) {
dp2[i][j]+=(dp2[k][j-1]+dp2[i-k-1][j-1]-dp2[k][j-1]*dp2[i-k-1][j-1])/i;
}
}
}
scanf("%d%d",&Q,&n);
if(Q==1) printf("%lf",dp[n-1]);
else {
db res=0;
for(int i=1;i<=n-1;i++) {
res+=dp2[n-1][i];
}
printf("%lf",res);
}
}