[SHOI2012]随机树

Posted guessycb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SHOI2012]随机树相关的知识,希望对你有一定的参考价值。

[SHOI2012]随机树

题目大意( 网址戳我! )

随机树是一颗完全二叉树,初始状态下只有一个节点。
随机树的生成如下:每次随机选择一个叶子节点,扩展出两个儿子。
现在给定一个正整数\(n\)(\(n \le 100\)) , 询问叶子节点个数\(n\)的随机树:

  • \(q = 1\)叶子节点的平均深度
  • \(q = 2\)整棵随机树的平均深度

样例:\(cin\ q\ n\ \ \ \ ;cin\ 1\ 4\ ,\ put\ 2.166667\ \ \ ;\ \ \ cin \ 2 \ 4\ ,\ put\ 2.666667\ \ \ ;\)

解题思路

\(solve_a\)\(q = 1\) (叶子节点平均深度)

\(f(x)\)表示扩展了\(x\)次后的叶子节点平均深度。
那么求\(f(x)\)时 , 直接把新扩展的节点深度设为 \(f(x-1)\) 不就行了吗?
转移:
\(f(x) = \frac{1}{x} (\ f(x-1)*(x-1) - f(x - 1) + (f(x-1)+1)*2\ )\)
把它展开后:
\(f(x) = f(x - 1) + \frac{2}{x}\) , 初始值:\(f(0) = 0\) ;

\(solve_b\)\(q = 2\) (整棵树的平均深度)

整数概率公式:\(E(x) = \sum_{i=1}^{\infty} P(x \ge i)\)
所以只要求随机树层数大于等于\(i\)层的概率即可。
我们脱离扩展,改为构建一颗有\(n\)个叶子节点,问层数大于等于\(i\)层的概率。
\(f[x][d]\)表示有\(x\)个叶节点,树深度大于等于\(d\)的概率。
那么每次通过添加根来提升层数 , 枚举左右儿子分配多少个叶子节点即可。
转移:
\[f[x][d] = \frac{1}{x-1}\sum_{i=1}^{x-1} = f[i][d-1] + f[x-i][d-1] - f[i][d-1]*f[x-i][d-1]\]
就是小学容斥原理 , 然后初值为:\(f[x][0] = 1.0\)

实现代码:

#include<bits/stdc++.h>
#define RG register
#define IL inline
#define _ 101
using namespace std;

double f[_][_],res,ans; int q , n ; 

IL void solve1(){
    for(RG int i = 2; i <= n; i ++) res += 2.0 / (double)i ;
    printf("%.6lf" , res) ;  return ; 
}
IL void solve2(){
    for(RG int x = 1; x <= n; x ++)f[x][0] = 1.0;
    for(RG int x = 2; x <= n; x ++)
        for(RG int d = 1; d <= x ; d ++){
            for(RG int l = 1; l <= x - 1; l ++)
                f[x][d] += f[l][d-1] + f[x-l][d-1] - f[l][d-1]*f[x-l][d-1] ;
            f[x][d] /= (double)(x - 1) ; 
        }
    ans = 0; for(RG int i = 1; i <= n; i ++)ans += f[n][i] ;
    printf("%.6lf" , ans) ;  return ;
}

int main(){
    cin >> q ; cin >> n;
    (q & 1) ? solve1() : solve2() ;
    return 0;
}

以上是关于[SHOI2012]随机树的主要内容,如果未能解决你的问题,请参考以下文章

P3830 [SHOI2012]随机树

[SHOI2012]随机树

[SHOI2012]随机树

BZOJ2830 & 洛谷3830:[SHOI2012]随机树——题解

洛谷3830 [SHOI2012]随机树 概率dp

luogu P3830 [SHOI2012]随机树 期望 dp