zoukankan      html  css  js  c++  java
  • 【BZOJ2830/洛谷3830】随机树(动态规划)

    【BZOJ2830/洛谷3830】随机树(动态规划)

    题面

    洛谷

    题解

    先考虑第一问。
    第一问的答案显然就是所有情况下所有点的深度的平均数。
    考虑新加入的两个点,一定会删去某个叶子,然后新加入两个深度为原先叶子(+1)的点。
    那么新加入的叶子的深度的期望是未加入之前的期望+1,假设(f_i)(i)个点的期望。
    那么(f_i=(f_{i-1}*({i-1})-f_{i-1}+2*(f_{i-1}+1))/i=f_{i-1}+2/i)
    含义就是平均的深度乘上点的个数等于深度总和,减去删去的点的深度,加入两个新的深度为原先点(+1)的点。

    考虑第二问
    不难想到一个状态(f[i][j])表示拥有(i)个节点,深度为(j)的概率。
    那么答案就是(sum_{i=0}^nf[n][i]*i)
    这个转移不难,我们根节点已经固定,并且它一定拥有左右子树,我们转移的时候分开考虑左右子树,然后再在根节点的位置合并,即

    [f[i][max(k,l)+1] ightarrow f[j][k]*f[i-j][l]/(i-1) ]

    除掉(i-1)的原因是一开始我们直接把左右儿子都当成整棵树来看,所以最终合并的时候要把总方案除掉。

    还有一种做法,大同小异,然而复杂度更优秀。
    (f[i][j])表示(i)个叶子的树,深度至少为(j)的概率。
    转移和上面的东西类似,容斥去重。

    [f[i][j]=frac{1}{i-1}sum f[k][j-1]*1+f[i-k][j-1]*1-f[i][j-1]*f[i-k][j-1] ]

    答案是(sum f[n][i])

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,Q;
    double ans,f[101][101];
    int main()
    {
    	cin>>Q>>n;
    	if(Q==1)
    	{
    		for(int i=2;i<=n;++i)
    			ans+=2.0/i;
    		printf("%.6lf
    ",ans);
    	}
    	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;++j)
    				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])/(i-1);
    		for(int i=1;i<=n;++i)ans+=f[n][i];
    		printf("%.6lf
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    背景(北极狐)
    【面试】java基础
    C#分享海报生成
    jetson nano 4gb记录
    jetson nano 2gb相关问题
    分布式系列-分布式ID
    Mybatis-Plus 多租户模式忽略某个方法
    IDEA 集成 Docker 插件实现一键远程部署 SpringBoot 应用,无需三方依赖,开源微服务全栈有来商城线上部署方式
    《将博客搬至CSDN》
    elk收集docker容器的json格式日志
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9677482.html
Copyright © 2011-2022 走看看