HDU 5378 树上的概率DP Leader in Tree Land

官方题解

可以用求概率的思想来解决这个问题。令以i号节点为根的子树为第i棵子树,设这颗子树恰好有sz[i]个点。那么第i个点是第i棵子树最大值的概率为1/sz[i],不是最大值的概率为(sz[i]-1)/sz[i]。现在可以求解恰好有k个最大值的概率。

令dp[i][j]表示考虑编号从1到i的点,其中恰好有j个点是其子树最大值的概率。 很容易得到如下转移方程:dp[i][j]=dp[i-1][j]*(sz[i]-1)/sz[i]+dp[i-1][j-1]/sz[i]。这样dp[n][k]就是所有点中恰好有k个最大值的概率。

题目要求的是方案数,用总数n!乘上概率就是答案。计算的时候用逆元代替上面的分数即可

另外我补充一下边界情况:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 using namespace std;
 7 
 8 typedef long long LL;
 9 
10 const int maxn = 1000 + 10;
11 const LL MOD = 1000000007;
12 
13 LL fac[maxn], invfac[maxn], inv[maxn];
14 
15 inline LL mul_mod(LL a, LL b) { return (a * b) % MOD; }
16 
17 LL pow_mod(LL a, LL n)
18 {
19     LL ans = 1, base = a;
20     while(n)
21     {
22         if(n & 1) ans = mul_mod(ans, base);
23         base = mul_mod(base, base);
24         n >>= 1;
25     }
26     return ans;
27 }
28 
29 LL inverse(LL a) { return pow_mod(a, MOD - 2); }
30 
31 void preprocess()
32 {
33     fac[0] = 1;
34     for(int i = 1; i < maxn; i++) { inv[i] = inverse(i); fac[i] = (fac[i - 1] * i) % MOD; }
35     invfac[maxn - 1] = inverse(fac[maxn - 1]);
36     for(int i = maxn - 2; i >= 0; i--) invfac[i] = mul_mod(invfac[i+1], (i+1));
37 }
38 
39 vector<int> G[maxn];
40 
41 int sz[maxn];
42 
43 void dfs(int u, int fa)
44 {
45     sz[u] = 1;
46     for(int i = 0; i < G[u].size(); i++)
47     {
48         int v = G[u][i];
49         if(v == fa) continue;
50         dfs(v, u);
51         sz[u] += sz[v];
52     }
53 }
54 
55 LL d[maxn][maxn];
56 
57 int main()
58 {
59     preprocess();
60 
61     int T; scanf("%d", &T);
62     for(int kase = 1; kase <= T; kase++)
63     {
64         int n, k; scanf("%d%d", &n, &k);
65         for(int i = 1; i <= n; i++) G[i].clear();
66         for(int u, v, i = 1; i < n; i++)
67         {
68             scanf("%d%d", &u, &v);
69             G[u].push_back(v); G[v].push_back(u);
70         }
71 
72         dfs(1, 0);
73         d[1][0] = mul_mod(sz[1] - 1, inv[sz[1]]);
74         d[1][1] = inv[sz[1]];
75         for(int i = 2; i <= n; i++)
76         {
77             d[i][0] = mul_mod(mul_mod(d[i-1][0], sz[i] - 1), inv[sz[i]]);
78             for(int j = 1; j <= min(i, k); j++)
79             {
80                 LL t1 = mul_mod(mul_mod(d[i-1][j], sz[i] - 1), inv[sz[i]]);
81                 LL t2 = mul_mod(d[i-1][j-1], inv[sz[i]]);
82                 d[i][j] = t1 + t2;
83                 if(d[i][j] >= MOD) d[i][j] -= MOD;
84             }
85         }
86 
87         LL ans = mul_mod(d[n][k], fac[n]);
88         printf("Case #%d: %I64d\n", kase, ans);
89     }
90 
91     return 0;
92 }
代码君

 

posted @ 2015-08-14 15:22  AOQNRMGYXLMV  阅读(246)  评论(0编辑  收藏  举报