洛谷P3830,[SHOI2012]随机树,概率期望

正题

      题面戳这

      这题的题解都读了我半天呢///

      首先我们来讨论第一问。。

      我们设f_i表示叶子结点为i时的叶节点平均深度。那么我们猜想一下,每次插入前的树的叶节点总深度平均为f_{i-1}*(i-1),因为每棵树上面每个节点的平均深度就是f_{i-1}。另外我们讨论加点的平均深度。比如当前的树是左下角。  

      我们现在给它加上一个点,讨论其价值,平均每个点的深度是f_{i-1},我们就当作 这个点放在深度为f_{i-1}的叶子节点上,那么原来的叶子节点会被覆盖,取而代之的是两个比它深度多1的节点。所以多出来的就是2*f_{i-1}+2-f_{i-1}=f_{i-1}+2,然后我们再与前面的总深度f_{i-1}*(i-1) 加起来,除以x, 就是当前叶子的平均深度。

      后面求树深度的期望。

      用f_{i,j}表示有i个叶子节点,深度>=j的概率。

      那么很明显预处理f_{i,0}都为1,因为深度不可能小于0;

      继续往下推 f_{i,j}=\sum _{k=1}^{n-1}f_{k,j-1}+f_{i-k,j-1}-f_{k,j-1}*f_{i-k,j-1};

      我们不断地枚举左边子树的大小,然后令左右子树有一个深度>=j-1,都大于等于也行,但是会重复算,所以要减去两个相乘。

       最后的答案就是ans=\sum_{k=1}^{n-1}f_{n,k}

       因为第k个会被前面算k遍,就相当于给深度为k的概率乘上一个k。

代码简单看看就行,关键还是理解。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;

int n,q;
double f[110][110];

int main(){
	scanf("%d %d",&q,&n);
	if(q==1){
		double ans=0;
		for(double i=2;i<=n;i++) ans+=2/i;
		printf("%lf",ans);
		return 0;
	}
	else{
		for(int i=1;i<=n;i++) f[i][0]=1;	
		for(int i=2;i<=n;i++)
			for(int j=1;j<i;j++){
				for(int k=1;k<i;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;
		for(int i=1;i<n;i++) ans+=f[n][i];
		printf("%lf",ans);
	}
}

其实你再给我一道这样的题,我还是不会的。要多积累啊!!

猜你喜欢

转载自blog.csdn.net/Deep_Kevin/article/details/81669702