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();
}

浙公网安备 33010602011771号