• [SHOI2012]随机树


    XXVII.[SHOI2012]随机树

    \(q=1\)

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

    \(f_i=f_{i-1}+\dfrac{2}{i}\)

    证明:

    我们随便从\(i-1\)个叶子中选一个出来,展开它,

    则这次展开期望能为叶子的深度和增加\(2*(f_{i-1}+1)-f_{i-1}\)

    但是还要重新取平均;

    于是

    \(f_i=\dfrac{f_{i-1}*(i-1)+2*(f_{i-1}+1)-f_{i-1}}{i}\)

    化简就得到了

    \(f_i=f_{i-1}+\dfrac{2}{i}\)

    \(q=2\)

    考虑令\(f[i][j]\)表示:

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

    显然,有\(f[i][j]=\sum\limits_{k=1}^{i-1}\dfrac{f[k][j-1]+f[i-k][j-1]-f[k][j-1]*f[i-k][j-1]}{?}\)

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

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

    考虑这种可能性的大小。

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

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

    则可能性的大小为\(g_{k}*g_{i-k}*C_{i-2}^{k-1}=(k-1)!*(i-k-1)!*\dfrac{(i-2)!}{(k-1)!*(i-2-k+1)!}=(i-2)!\)

    然后分母上的\(?\)就是\(\dfrac{g_i}{(i-2)!}=\dfrac{(i-1)!}{(i-2)!}=(i-1)\)

    于是我们现在有

    \(f[i][j]=\sum\limits_{k=1}^{i-1}\dfrac{f[k][j-1]+f[i-k][j-1]-f[k][j-1]*f[i-k][j-1]}{i-1}\)

    有一个式子:

    \(E(x)=\sum\limits_{i=1}^{\infty}P(i)\)

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

    证明:

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

    \(E(x)=\sum\limits_{i=1}^{\infty}p(i)*i\)

    \(P(i)=\sum\limits_{j=i}^{\infty}p(j)\)

    \(\begin{aligned}\sum\limits_{i=1}^{\infty}P(i)&=\sum\limits_{i=1}^{\infty}\sum\limits_{j=i}^{\infty}p(j)\\&=\sum\limits_{i=1}^{\infty}p(i)*i\\&=E(x)\end{aligned}\)

    证毕。

    依据此式,则答案为\(\sum\limits_{i=1}^{n-1}f[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;
    }
    

  • 相关阅读:
    使用java中的注解@see
    MacOS软件默认安装路径
    学习MACD指标
    go CD 用虚拟机快速增加一个新agent
    git推送本地分支到远程分支
    git如何切换远程仓库
    git命令查看远程分支
    Java 学习札记(一)JDK安装配置
    Oracle 基本操作符
    C# 常用控件属性及方法介绍
  • 原文地址:https://www.cnblogs.com/Troverld/p/14597025.html
Copyright © 2020-2023  润新知