把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P3830 [SHOI2012]随机树

题面传送门
先看第一问,设\(f_i\)\(i\)次操作后的深度总和。
考虑选择一个点让它扩展,那么得到的叶子节点的期望深度就是\(\frac{f_{i}}{i+1}+2\),就可以\(O(n)\)解决问题了。
再看第二问,设\(f_{i,j}\)\(i\)次操作,深度为\(j\)的概率。
枚举左边子树的操作数\(k\),再枚举左右两边的深度\(d1,d2\)。就可以得到转移\(f_{i,\max(d1,d2)+1}=\frac{f_{j,d1}\times f_{i-j-1,d2}}{i}\)
前缀和一下就可以做到\(O(n^3)\)
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N (100+5)
#define M 5000000
#define mod 1000000007
#define Mod (mod-1)
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int op,n;
namespace Solve1{
	db dp[N+5];I void S1(){
		RI i,j;n--;dp[0]=0;for(i=1;i<=n;i++)dp[i]=dp[i-1]+2.0/(i+1);printf("%.6lf\n",dp[n]);
	}
}
namespace Solve2{
	db dp[N+5][N+5],Ns,Ans;I void S2(){
		n--;RI i,j,h;dp[0][0]=1;for(i=1;i<=n;i++){
			for(j=0;j<i;j++){
				Ns=0;for(h=0;h<=j;h++) Ns+=dp[i-j-1][h],dp[i][h+1]+=Ns*dp[j][h]/i;
				Ns=0;for(h=0;h<=i-j-1;h++) dp[i][h+1]+=Ns*dp[i-j-1][h]/i,Ns+=dp[j][h];
			}
		}for(i=1;i<=n;i++) Ans+=dp[n][i]*i;printf("%.6lf\n",Ans);
	}
}
int main(){
    freopen("1.in","r",stdin);
	scanf("%d%d",&op,&n);op^2?Solve1::S1():Solve2::S2();
}
posted @ 2022-03-13 20:51  275307894a  阅读(43)  评论(0)    收藏  举报
浏览器标题切换
浏览器标题切换end