[SHOI2012]随机树 洛谷P3803 【期望dp】

题面


SOL

分两个问题讨论;
Q1 :显然的期望dp定义式 : f [ i ] : 第 i 步 的 期 望 平 均 叶 子 深 度 f[i]:第i步的期望平均叶子深度 f[i]:i,
转移方程: f [ i ] = f [ i − 1 ] ∗ ( i − 1 ) + f [ i − 1 ] + 2 i , − > f [ i ] = f [ i − 1 ] + 2 i . {f[i]={f[i-1]*(i-1)+f[i-1]+2}\over{i}},->f[i]=f[i-1]+{2\over i}. if[i]=f[i1](i1)+f[i1]+2,>f[i]=f[i1]+i2.
可以再数学化简,这里没必要了。

Q2: 上一问好做,是因为我们可以直接从任意一个点转移。这一问要求最大深度的期望,如果要这样做,还要维护一个最大深度对应的叶子数。留作讨论吧。 。(updated, 9.23 ,这样定义状态包含了条件本身的概率,而子问题的条件和当前的条件不一样,不知道条件之间的转移概率,所以这个方法不行。)

从"拼树"的角度思考,一颗树由 一个根节点加左右两个子树拼接而成,左右子树是原问题的子问题,于是我们定义 f [ i ] [ j ] 表 示 有 i 个 叶 子 节 点 的 树 , 深 度 为 j 的 概 率 f[i][j]表示有i个叶子节点的树,深度为j的概率 f[i][j]ij

那么枚举左右两子树,加上当前根节点就可以直接转移了。(注意本题特殊性,还要乘以生成左右子树叶节点树对应的概率)

法一:

f [ i ] [ j ] = ∑ L = 1 i − 1 p [ i ] [ L ] ∗ ( ∑ k = 1 j − 1 f [ L ] [ j − 1 ] ∗ f [ i − L ] [ k ] + ∑ k = 1 j − 1 f [ L ] [ k ] ∗ f [ i − L ] [ j − 1 ] − f [ L ] [ j − 1 ] ∗ f [ i − L ] [ j − 1 ] ) f[i][j]=\sum_{L=1}^{i-1}p[i][L]*(\sum_{k=1}^{j-1}f[L][j-1]*f[i-L][k]+\sum_{k=1}^{j-1}f[L][k]*f[i-L][j-1]-f[L][j-1]*f[i-L][j-1]) f[i][j]=L=1i1p[i][L](k=1j1f[L][j1]f[iL][k]+k=1j1f[L][k]f[iL][j1]f[L][j1]f[iL][j1])
p [ i ] [ j ] = p [ i − 1 ] [ j − 1 ] ∗ j − 1 i − 1 + p [ i − ] [ j ] ∗ ( 1 − j i − 1 ) p[i][j]=p[i-1][j-1]*{{j-1}\over{i-1}}+p[i-][j]*(1-{j\over{i-1}}) p[i][j]=p[i1][j1]i1j1+p[i][j](1i1j)
这里 f f f数组可以前缀和转移优化, O ( n 3 ) O(n^3) O(n3)统计答案: a n s = ∑ j = 1 n − 1 f [ n ] [ j ] ∗ j . ans = \sum_{j=1}^{n-1}f[n][j]*j. ans=j=1n1f[n][j]j.

法二

使用全期望公式:
f [ i ] [ j ] : i 个 叶 节 点 的 子 树 , 深 度 大 于 等 于 j 的 概 率 f[i][j]:i个叶节点的子树,深度大于等于j的概率 f[i][j]:ij
a n s = ∑ i = 1 n − 1 f [ n ] [ i ] ans=\sum_{i=1}^{n-1}f[n][i] ans=i=1n1f[n][i].
转移有:
f [ i ] [ j ] = ∑ L = 1 i − 1 p [ i ] [ L ] ∗ ( f [ L ] [ j − 1 ] + f [ i − L ] [ j − 1 ] − f [ L ] [ j − 1 ] ∗ f [ i − L ] [ j − 1 ] ) f[i][j]=\sum_{L=1}^{i-1}p[i][L]*(f[L][j-1]+f[i-L][j-1]-f[L][j-1]*f[i-L][j-1]) f[i][j]=L=1i1p[i][L](f[L][j1]+f[iL][j1]f[L][j1]f[iL][j1])
一样 O(n^3)解决 (左右子树都大于等于 j − 1 j-1 j1的概率被算了两次,减掉即可)

PS

p [ i ] [ k = 1... i − 1 ] p[i][k=1...i-1] p[i][k=1...i1] 其实就等于 1 i − 1 {1\over{i-1}} i11
证明:
先选左右子树,生成选法序列,再在子树里选叶节点,生成选树数列。

对于 p [ i ] [ j ] p[i][j] p[i][j]
从1个叶子节点开始构造,每次选L,L增加一个,选R,R增加一个;
总共选了 k 个 L ,选的方案是 ( i − 2 k ) {i-2}\choose k (ki2),为 ( i − 2 ) ! ( i − 2 − k ) ! ∗ k ! {{(i-2)!}\over{(i-2-k)! * k!}} (i2k)!k!(i2)!.

对于子树的拼接方案,左子树叶节点从1 到 k k k,总共 k ! k! k!总生成方法。同理,右子树总共 ( i − 2 − k ) ! (i-2-k)! (i2k)!种生成方法。
所以总的选法是序列生成方案*子树生成方案,为 ( i − 2 ) ! ( i − 2 − k ) ! ∗ k ! ∗ k ! ∗ ( i − 2 − k ) ! = ( i − 2 ) ! {{(i-2)!}\over{(i-2-k)! * k!}}*k!*(i-2-k)!=(i-2)! (i2k)!k!(i2)!k!(i2k)!=(i2)!

所以总方案数和左右儿子个数无关, p [ i ] [ j ] = 1 i − 1 p[i][j]={1\over{i-1}} p[i][j]=i11.
证毕。


CODE

#include<bits/stdc++.h>
#define pf printf
#define sf scanf
#define cs const
#define ll long long
#define db double
#define ri register int
using namespace std;
cs int N=110;
db p[N][N],f[N][N],g[N];
int n;
inline void init_p(){
	p[2][1]=1;
	for(ri i=3;i<=n;++i){
		for(ri j=1;j<i;++j){
			p[i][j]=p[i-1][j-1]*(j-1)/(1.0*(i-1))+p[i-1][j]*(1.0-1.0*j/(1.0*(i-1)));
		}
	}
}
inline void init_f(){
	f[1][0]=1;
	for(ri i=2;i<=n;++i){
		f[i][1]=1;
		for(ri j=2;j<i;++j){
			for(ri k=1;k<i;++k){
				f[i][j]+=p[i][k]*(f[k][j-1]+f[i-k][j-1]-f[k][j-1]*f[i-k][j-1]);
			}
		}
	}
	db ans=0;
	for(ri i=1;i<n;++i)ans+=f[n][i];
	printf("%.6lf",ans);
}
inline void init_g(){
	g[1]=0;
	for(ri i=2;i<=n;++i)g[i]=g[i-1]+2.0/(1.0*i);
	printf("%.6lf",g[n]);
}
signed main (){
	int q;sf("%d%d",&q,&n);
	if(q==1)init_g();
	if(q==2)init_p(),init_f();
	return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值