[SHOI2012]随机树

XXVII.[SHOI2012]随机树

q=1

考虑令fi表示:一棵有i个叶节点的树,叶节点平均深度的期望值。

fi=fi1+2i

证明:

我们随便从i1个叶子中选一个出来,展开它,

则这次展开期望能为叶子的深度和增加2(fi1+1)fi1

但是还要重新取平均;

于是

fi=fi1(i1)+2(fi1+1)fi1i

化简就得到了

fi=fi1+2i

q=2

考虑令f[i][j]表示:

一棵有i个叶节点的树,深度j的概率。

显然,有f[i][j]=k=1i1f[k][j1]+f[ik][j1]f[k][j1]f[ik][j1]?

释义:我们枚举左子树中放进去k个子节点。则左/右节点至少有一个深度j1的状态都是合法的。但是,左右节点深度都j1的情况在两个中都被算进去了;因此需要减去这种可能。

这个分母上的?,就是出现这种左右子树size分配的可能性。

考虑这种可能性的大小。

我们设gi表示构成一棵有i个叶节点的树的方案数。则有gi=(i1)!,因为每“扩展”一个点就相当于从i个叶子中选了一个叶子出来,有i种选法;则有gi=j=1i1j=(i1)!

显然,这种可能性应该等于gkgik?(这个?是一个新的?)。我们将两棵子树合并,首先两棵子树自己内部扩展的顺序已经被g决定了;但是合并的顺序可是可以随便指定的;合并顺序的种数等于Ci2k1,因为i个叶节点就意味着i2次合并(当前节点自己本身就占用一次合并),这i2次合并选出k1次合并在左子树上。

则可能性的大小为gkgikCi2k1=(k1)!(ik1)!(i2)!(k1)!(i2k+1)!=(i2)!

然后分母上的?就是gi(i2)!=(i1)!(i2)!=(i1)

于是我们现在有

f[i][j]=k=1i1f[k][j1]+f[ik][j1]f[k][j1]f[ik][j1]i1

有一个式子:

E(x)=i=1P(i)

其中E(x)表示x的期望,P(i)表示ix的概率。

证明:

p(i)表示i=x的概率,P(i)表示ix的概率,

E(x)=i=1p(i)i

P(i)=j=ip(j)

i=1P(i)=i=1j=ip(j)=i=1p(i)i=E(x)

证毕。

依据此式,则答案为i=1n1f[n][i]

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m;
namespace T1{
	double f[110];
	double work(){
		f[1]=0;
		for(int i=2;i<=n;i++)f[i]=f[i-1]+2.0/i;
		return f[n];
	}
}
namespace T2{
	double f[110][110];
	double work(){
		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[i-k][j-1]+f[k][j-1]-f[i-k][j-1]*f[k][j-1];
			f[i][j]/=i-1;
		}
		double res=0;
		for(int i=1;i<n;i++)res+=f[n][i];
		return res;
	}
} 
int main(){
	scanf("%d%d",&m,&n);
	if(m==1)printf("%lf\n",T1::work());
	if(m==2)printf("%lf\n",T2::work());
	return 0;
}

posted @   Troverld  阅读(99)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示