luogu P3830 [SHOI2012]隨機樹
阿新 • • 發佈:2022-03-13
題面傳送門
先看第一問,設\(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(); }