洛谷3830 BZOJ2830 SHOI2012 随机树 概率期望 dp 组合数学

19 篇文章 0 订阅
18 篇文章 0 订阅

题目链接

题意:
有两问,第一问是所有可能的 n n n个叶子节点的二叉树的叶节点的平均深度,第二问是 n n n个叶节点的二叉树的期望深度。 n &lt; = 100 n&lt;=100 n<=100,结果保留 6 6 6位小数。

题解:
我们一问一问的来做。

首先考虑第一问。我们设 f [ i ] f[i] f[i]表示有 i i i个叶子的二叉树的平均深度。我们考虑把一个叶子节点展开之后的影响。我们的想法是,用总深度除以叶子数。我们发现我们可以算出新增加的叶子的平均深度,我们把原来的某一个叶子变成一个非叶子节点,然后增加了两个深度是原来叶子节点深度 + 1 +1 +1的节点,平均来讲,变化量就是 − f [ i ] + 2 ∗ ( f [ i ] + 1 ) = f [ i ] + 2 -f[i]+2*(f[i]+1)=f[i]+2 f[i]+2(f[i]+1)=f[i]+2。我们用原来的平均总深度加上多了一个叶子后的平均深度增加量除以叶子总数就应该是新的平均总深度,列出式子就是 f [ i ] = f [ i − 1 ] ∗ ( i − 1 ) + f [ i ] + 2 i = f [ i − 1 ] ∗ i + 2 i = f [ i − 1 ] + 2 i f[i]=\frac{f[i-1]*(i-1)+f[i]+2}{i}=\frac{f[i-1]*i+2}{i}=f[i-1]+\frac{2}{i} f[i]=if[i1](i1)+f[i]+2=if[i1]i+2=f[i1]+i2

这样就可以 O ( n ) O(n) O(n)的递推一下得到最终结果了。

然后考虑第二问。这个第二问就比较有难度了。我们一个简单的想法是设 d p [ i ] [ j ] dp[i][j] dp[i][j]表示考虑了 i i i个叶子,最大深度是 j j j的概率,这样最终答案就是 ∑ i = 1 n − 1 d p [ n ] [ i ] ∗ i \sum_{i=1}^{n-1}dp[n][i]*i i=1n1dp[n][i]i。但是我们发现这个式子不太好转移。

有一个巧妙的式子是,我们设 d p [ i ] [ j ] dp[i][j] dp[i][j]表示现在有 i i i个叶子,最大深度大于等于 j j j的概率。这样设的话,答案就是 ∑ i = 1 n − 1 d p [ n ] [ i ] \sum_{i=1}^{n-1}dp[n][i] i=1n1dp[n][i],因为深度为 x x x的大于等于 1 − x 1-x 1x的每一个,会在 d p [ n ] [ 1 ] dp[n][1] dp[n][1] d p [ n ] [ x ] dp[n][x] dp[n][x]都被统计进去一遍,于是会被算正好 x x x遍,就不用容斥也不用乘权值了。

我们考虑这个式子怎么转移。我们要从最大深度大于等于 j − 1 j-1 j1的转移到最大深度大于等于 j j j的。我们枚举左子树有多少个叶子,设为 k k k,这样我们可以算出右子树的叶子,只要之前那么多叶子的左右子树有一个深度大于等于 j − 1 j-1 j1,那么原树就算是深度大于等于 j − 1 j-1 j1。我们用两者的概率相加,发现都大于等于 j − 1 j-1 j1的部分被算了两遍,要减去一遍。那么我们用这个概率乘 i i i个叶子,左子树有 k k k个叶子的概率,设为 p p p,最后累加一下就是答案。列出式子就是 d p [ i ] [ j ] = ∑ k = 1 i − 1 p ∗ ( d p [ k ] [ j − 1 ] + d p [ i − k ] [ j − 1 ] − d p [ k ] [ j − 1 ] ∗ d p [ i − k ] [ j − 1 ] ) dp[i][j]=\sum_{k=1}^{i-1}p*(dp[k][j-1]+dp[i-k][j-1]-dp[k][j-1]*dp[i-k][j-1]) dp[i][j]=k=1i1p(dp[k][j1]+dp[ik][j1]dp[k][j1]dp[ik][j1])

现在的问题是求出 p p p,只要能求出 p p p,我们就可以在 O ( n 3 ) O(n^3) O(n3)的时间里求出答案。我们考虑第一次操作一定是展开根,变成左右子树都有一个叶子的情况。每一次操作会使一个叶子不再是叶子,并产生两个新的叶子,于是每次操作叶子数会加一,于是 i i i个叶子的树是经过了 i − 1 i-1 i1次操作,除掉第一次对根的操作外,每次操作的要么是左子树,要么是右子树,共 i − 2 i-2 i2次。我们考虑用要求的情况的方案数除以总的方案数来表示这个概率。我们在这 i − 2 i-2 i2次操作中操作了左子树 k − 1 k-1 k1次,并且这 k − 1 k-1 k1次操作可以形成不同的形态的树。对于 i − 2 i-2 i2次操作了左子树 k − 1 k-1 k1次,方案数就是 C i − 2 k − 1 C_{i-2}^{k-1} Ci2k1。我们考虑形成 i i i个叶子的树的方案数(这里形成的树的形态可能相同)。我们要展开 n − 1 n-1 n1次,我们第一次只能展开根,第二次有两个不同的叶子可以选,第三次有三个叶子可以选,第 n − 1 n-1 n1次有 n − 1 n-1 n1个叶子可以选,于是方案数应该是 ( n − 1 ) ! (n-1)! (n1)!种。那么我们就能列出式子了: p = C i − 2 k − 1 ∗ ( k − 1 ) ! ∗ ( i − k − 1 ) ! ( i − 1 ) ! p=\frac{C_{i-2}^{k-1}*(k-1)!*(i-k-1)!}{(i-1)!} p=(i1)!Ci2k1(k1)!(ik1)! = ( i − 2 ) ! ( k − 1 ) ! ∗ ( ( i − 2 ) − ( k − 1 ) ) ! ∗ ( k − 1 ) ! ∗ ( i − k − 1 ) ! ( i − 1 ) ! =\frac{\frac{(i-2)!}{(k-1)!*((i-2)-(k-1))!}*(k-1)!*(i-k-1)!}{(i-1)!} =(i1)!(k1)!((i2)(k1))!(i2)!(k1)!(ik1)! = ( i − 2 ) ! ( k − 1 ) ! ∗ ( i − k − 1 ) ! ∗ ( k − 1 ) ! ∗ ( i − k − 1 ) ! ( i − 1 ) ! =\frac{\frac{(i-2)!}{(k-1)!*(i-k-1)!}*(k-1)!*(i-k-1)!}{(i-1)!} =(i1)!(k1)!(ik1)!(i2)!(k1)!(ik1)! = ( i − 2 ) ! ( i − 1 ) ! = 1 i − 1 =\frac{(i-2)!}{(i-1)!}=\frac{1}{i-1} =(i1)!(i2)!=i11 于是我们推出最后的概率与 k k k无关,始终是 1 i − 1 \frac{1}{i-1} i11

那么我们带回原式,就得到是dp式子: d p [ i ] [ j ] = ∑ k = 1 i − 1 d p [ k ] [ j − 1 ] + d p [ i − k ] [ j − 1 ] − d p [ k ] [ j − 1 ] ∗ d p [ i − k ] [ j − 1 ] i − 1 dp[i][j]=\sum_{k=1}^{i-1}\frac{dp[k][j-1]+dp[i-k][j-1]-dp[k][j-1]*dp[i-k][j-1]}{i-1} dp[i][j]=k=1i1i1dp[k][j1]+dp[ik][j1]dp[k][j1]dp[ik][j1]

这样就做完第二问了。复杂度是 O ( n 3 ) O(n^3) O(n3)

代码:

#include <bits/stdc++.h>
using namespace std;

int n,q;
double dp[110][110],f[110],ans;
int main()
{
	scanf("%d%d",&q,&n);
	if(q==1)
	{
		f[1]=0;
		for(int i=2;i<=n;++i)
		f[i]=f[i-1]+2.0/(double)i;
		printf("%.6lf\n",f[n]);
	}
	else
	{
		for(int i=1;i<=n;++i)
		dp[i][0]=1;
		for(int i=2;i<=n;++i)
		{
			for(int j=1;j<=i-1;++j)
			{
				for(int k=1;k<=i-1;++k)
				dp[i][j]+=1.0/(double)(i-1)*(dp[k][j-1]+dp[i-k][j-1]-dp[k][j-1]*dp[i-k][j-1]);
			}
		}
		for(int i=1;i<=n-1;++i)
		ans+=dp[n][i];
		printf("%.6lf\n",ans);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值