zoukankan      html  css  js  c++  java
  • luogu3830 [SHOI2012]随机树

    传送门:洛谷

    题目大意:对于一个只有一个节点的二叉树,一次操作随机将这棵树的叶节点的下方增加两个节点。$n-1$次操作后变为$n$个叶节点的二叉树。求:(1)叶节点平均深度的期望值(2)树深度的数学期望值

    数据范围:$2leq nleq 100$


    首先看第(1)问

    设$f_i$为$i$个叶节点的二叉树的叶节点平均深度的期望值。

    每次选择一个叶节点,扩展出两个新的叶节点,所以总的深度增加$f_{i-1}+2$

    则$f_i=frac{(i-1)*f_{i-1}+f_{i-1}+2}{i}=f_{i-1}+frac{2}{i}$

    所以

    $$Ans=sum_{i=2}^nfrac{2}{i}$$


    然后是第(2)问,这个难度要稍微大一点。

    我们发现这求的是$n$个数的最大值的期望,而第(1)问的是和的期望,而期望可加,却不能$max$,就非常不好办了。

    这时我们就需要用一个式子

    $$E[X]=sum_{i=1}^{n-1}P(Xgeq i)$$

    然后就可以转化为其中一个数$geq i$的概率。

    就很容易想到$dp[i][j]$表示$i$个叶节点的二叉树中深度$geq j$,则左子树深度$geq j-1$或右子树深度$geq j-1$

    所以

    $$dp[i][j]=frac{sum_{k=1}^{i-1}(dp[k][j-1]+dp[i-k][j-1]-dp[k][j-1]*dp[i-k][j-1])}{i-1}$$

    $$Ans=sum_{i=1}^{n-1}dp[n][i]$$

    然后就做完了。

     1 #include<cstdio>
     2 #define Rint register int
     3 using namespace std;
     4 const int N = 103;
     5 int q, n;
     6 double dp[N][N], ans;
     7 int main(){
     8     scanf("%d%d", &q, &n);
     9     if(q == 1)
    10         for(Rint i = 2;i <= n;i ++) ans += 2.0 / i;
    11     else {
    12         for(Rint i = 1;i <= n;i ++) dp[i][0] = 1;
    13         for(Rint i = 2;i <= n;i ++){
    14             for(Rint j = 1;j < n;j ++){
    15                 for(Rint k = 1;k < i;k ++)
    16                     dp[i][j] += dp[k][j - 1] + dp[i - k][j - 1] - dp[k][j - 1] * dp[i - k][j - 1];
    17                 dp[i][j] /= i - 1;
    18             }
    19         }
    20         for(Rint i = 1;i < n;i ++) ans += dp[n][i];
    21     }
    22     printf("%.6f", ans);
    23 }
    Luogu3830
  • 相关阅读:
    Azure Bicep(三)变量控制
    FreeRedis分布式锁实现以及使用
    动态表单存储设计
    SixLabors.ImageSharp 实践小结
    你了解一条sql的执行顺序吗
    理解ASP.NET Core
    理解ASP.NET Core
    产品说,我只需要一个有亿点复杂的查询界面
    学习大数据可以考哪些证书(附资料)
    数据治理之元数据管理的利器——Atlas入门宝典
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/10595583.html
Copyright © 2011-2022 走看看