洛谷 P3830 [SHOI2012]随机树

https://www.luogu.org/problemnew/show/P3830

具体方法见代码。。

其实挺神奇的,概率可以先算出“前缀和”(A小于等于xxx的概率),然后再“差分”得到A恰好为xxx的概率

话说推了很久“x个叶子节点的树,左子树有y个节点”的概率的dp,推不出来,然后无意间手玩了一下5个叶子节点,发现这个东西其实就等于1/(x-1),跟y没有关系。。。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<vector>
 5 using namespace std;
 6 #define fi first
 7 #define se second
 8 #define mp make_pair
 9 #define pb push_back
10 typedef long long ll;
11 typedef unsigned long long ull;
12 typedef pair<int,int> pii;
13 typedef long double ldb;
14 int q,n;
15 /*
16 int calc(int x,int y)//x个叶节点的树,左子树y个叶节点的概率
17 {
18     return ldb(1)/(x-1);
19 }
20 */
21 ldb an[110][110];
22 //an[i][j]表示i个叶节点的树,所有节点深度<=j的概率
23 bool v1[110][110];
24 ldb ans;
25 ldb dfs(int x,int y)
26 {
27     if(x==1)    return 1;
28     if(y==0)    return 0;
29     if(v1[x][y])    return an[x][y];
30     ldb ans=0;int i;
31     for(i=1;i<x;i++)
32         //ans+=calc(x,i)*dfs(
33         ans+=dfs(i,y-1)*dfs(x-i,y-1);
34     v1[x][y]=1;
35     return an[x][y]=ans/(x-1);
36 }
37 int main()
38 {
39     int i;ldb t;
40     scanf("%d%d",&q,&n);
41     if(q==1)
42     {
43         t=0;
44         for(i=2;i<=n;i++)
45         {
46             t+=2.0/i;
47         }
48         printf("%.6Lf",t);
49     }
50     else
51     {
52         for(i=1;i<n;i++)
53         {
54             ans+=i*(dfs(n,i)-dfs(n,i-1));
55         }
56         printf("%.6Lf",ans);
57     }
58     return 0;
59 }
View Code
原文地址:https://www.cnblogs.com/hehe54321/p/9812482.html