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
#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