玩具

本文探讨了在从一个初始点开始,通过n-1次等概率选择已有点进行连接,生成一棵随机树的过程中,如何计算该树高度的期望值。通过定义状态F[i][j]和G[i][j],并利用动态规划方法,详细推导了求解树高期望值的算法,同时提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

        翻译题意:一开始只有一个点,做n-1次操作:在已生成的点中等概率的挑一个。求最后生成的树的高的期望。

        我们可以设F[i][j]表示由i个点组成高不超过j的树的概率,G[i][j]表示由i个点组成高不超过j的森林的概率,此时我们考虑:在任意一种组成森林的方案中,我们用一个点连向森林中每一棵树的根节点,就正好对应了一种由i+1个点组成高不超过j+1的树的方案,即F[i][j]=G[i-1][j-1],则我们只考虑G的求法。

        转移很好转:G[i][j]=F[k][j]*G[i-k][j]=G[k-1][j-1]*G[i-k][j]。

        因为转移考虑到第一棵树的节点个数的分类,所以我们需要i个节点有j个节点在第一课树的概率,

        转移:dp[i][j]=dp[i-1][j-1]/i+dp[i-1][j]/i;

        另外注意极限情况的处理。

Code:

#include<bits/stdc++.h>
#define rep(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
template<typename T> void read(T &num){
    char c=getchar();T f=1;num=0;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){num=(num<<3)+(num<<1)+(c^48);c=getchar();}
    num*=f;
}
template<typename T> void qwq(T x){
    if(x>9)qwq(x/10);
    putchar(x%10+'0');
}
template<typename T> void write(T x){
    if(x<0){x=-x;putchar('-');}
    qwq(x);putchar('\n');
}
int n,p;
template<typename T> void chkmod(T &x,T y){x=(x+y)%p;}
int dp[210][210];int g[210][210];int inv[210];
inline void Pre(){
    inv[1]=1;
    rep(i,2,n){
        inv[i]=-(1ll*(p/i)*inv[p%i])%p;
        inv[i]=(inv[i]+p)%p;
    }
    return;
}
inline int G(int i,int j){
    if(i==0)return 1;
    if(j<0)return 0;
    return g[i][j];
}

int main(){
    read(n);read(p);
    dp[1][1]=1;Pre();
    if(n==1){
        write(0);return 0; 
    }else if(n==2){
        write(1);return 0;
    } 
    rep(i,2,n){
        rep(j,1,i){
            int tmp=(1ll*dp[i-1][j-1]*(j-1))%p;tmp=(1ll*tmp*inv[i])%p;
            chkmod(dp[i][j],tmp);
            tmp=(1ll*dp[i-1][j]*(i-j))%p;tmp=(1ll*tmp*inv[i])%p;
            chkmod(dp[i][j],tmp);
        }
    }
    
    rep(i,1,n-1){
        rep(j,0,i-1){
            rep(k,1,i){
                int tmp=(1ll*G(i-k,j)*G(k-1,j-1))%p;
                tmp=(1ll*tmp*dp[i][k])%p;chkmod(g[i][j],tmp);
            }
        }
        rep(j,i,n-2){g[i][j]=1;}
    }
    
    int ans=0;
    rep(i,0,n-2){
        int nop=(G(n-1,i)-G(n-1,i-1)+p)%p;nop=(1ll*nop*(i+1))%p;
        chkmod(ans,nop);
    }
    write(ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值