题目:https://www.luogu.org/problemnew/show/P3830
询问1:f[x]表示有x个叶节点的树的叶节点平均深度;
可以把被扩展的点的深度看做 f[x-1] ,于是两个新点深度为 f[x-1]+1,而剩下的x-2个点平均深度就是f[x-1];
所以f[x] = [ f[x-1] * (x-2) + (f[x-1] + 1) * 2 ] / x ;
整理得到f[x] = f[x-1] + 2 / x ;
询问2:f[i][j]表示有i个叶子节点、深度为j的概率;
把状态分成两个子状态,就是左子树和右子树,转移即可;
代码如下:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int q,n; double f[105][105],ans;//[叶子个数][深度] <[左子树叶子个数]> void solve1() { for(int i=2;i<=n;i++) ans+=2.0/i; printf("%.6lf ",ans); } void solve2() { f[1][0]=1; f[2][1]=1; f[3][2]=1; for(int i=4;i<=n;i++)//叶子个数 for(int j=1;j<i;j++)//左子树叶子个数 for(int k=0;k<j;k++)//左子树深度 for(int l=0;l<i-j;l++)//右子树深度 f[i][max(k,l)+1]+=f[j][k]*f[i-j][l]/(i-1); for(int i=1;i<=n;++i)ans+=i*f[n][i]; printf("%.6lf ",ans); } int main() { scanf("%d%d",&q,&n); if(q==1)solve1(); if(q==2)solve2(); return 0; }