luoguP3830 [SHOI2012]随机树 整数概率公式,概率Dp

luoguP3830 [SHOI2012]随机树

题目背景

SHOI2012 D1T3

题目描述

在这里插入图片描述

输入输出格式
输入格式:

输入仅有一行,包含两个正整数 q, n,分别表示问题编号以及叶结点的个数。

输出格式:

输出仅有一行,包含一个实数 d,四舍五入精确到小数点后 6 位。如果 q = 1,则 d 表示叶结点平均深度的数学期望值;如果 q = 2,则 d 表示树深度的数学期望值。

分析

沉迷概率无法自拔。
第一问:
f ( x ) f(x) f(x) x x x个叶节点的平均深度的期望
考虑选择一个节点拓展
f ( x + 1 ) = x f ( x ) + f ( x ) + 2 x + 1 = f ( x ) + 2 x + 1 f(x+1)=\frac{xf(x)+f(x)+2}{x+1}=f(x)+\frac{2}{x+1} f(x+1)=x+1xf(x)+f(x)+2=f(x)+x+12
递推一下就可以了。
第二问:
介绍一个公式

整数概率公式

E ( x ) = ∑ i = 1 i n f P ( x ≥ i ) E(x)=\sum_{i=1}^{inf}P(x\ge i) E(x)=i=1infP(xi)

它的意思是:正整数随机变量x的期望等于其分别大于等于所有数的概率之和。
证明:
根据期望的定义式,我们有
E ( x ) = ∑ i = 1 i n f i P ( x = i ) = ∑ i = 1 i n f i [ P ( x ≥ i ) − P ( x ≥ i + 1 ) ] = ∑ i = 1 i n f P ( x ≥ i ) E(x)=\sum_{i=1}^{inf}iP(x=i)=\sum_{i=1}^{inf}i[P(x\ge i)-P(x\ge i +1)]=\sum_{i=1}^{inf}P(x\ge i) E(x)=i=1infiP(x=i)=i=1infi[P(xi)P(xi+1)]=i=1infP(xi)
Q . E . D Q.E.D Q.E.D
回到本题,设 f [ x ] [ d ] f[x][d] f[x][d]表示有 x x x个叶子节点深度超过 d d d的概率。
考虑某个节点拓展的左右子节点。
用容斥原理可以得到方程。
f [ x ] [ d ] = f [ k ] [ d − 1 ] + f [ x − k ] [ d − 1 ] − f [ k ] [ d − 1 ] ⋅ f [ x − k ] [ d − 1 ] f[x][d]=f[k][d-1]+f[x-k][d-1]-f[k][d-1]\cdot f[x-k][d-1] f[x][d]=f[k][d1]+f[xk][d1]f[k][d1]f[xk][d1]
转移一波然后 A n s = ∑ i = 1 n − 1 f [ n ] [ i ] Ans=\sum_{i=1}^{n-1}f[n][i] Ans=i=1n1f[n][i]

代码

#include<cstdio>
const int N = 110;
int ri() {
    char ch = getchar(); int x = 0, f = 1;
    for(;ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f  = -1;
    for(;ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) - '0' + ch;
    return x * f;
}
double g[N], f[N][N];
int main() {
    int q = ri(), n = ri();
    if(q == 1) {
        for(int i = 2;i <= n; ++i) g[i] = g[i - 1] + 2.0 / i;
        printf("%.6lf\n", g[n]);
    }
    else {
        for(int i = 1;i <= n; ++i) f[i][0] = 1;
        for(int i = 2;i <= n; ++i) 
            for(int j = 1;j < i; f[i][j++] /= i - 1)
                for(int k = 1; k < i; ++k)
                    f[i][j] += f[k][j - 1] + f[i - k][j - 1] - f[k][j - 1] * f[i - k][j - 1];
        double r = 0;
        for(int i = 1;i < n; ++i) r += f[n][i];
        printf("%.6lf\n", r);
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值