shjwudp

导航

 

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5378

题意:给你一棵n个结点的有根树。因为是有根树,那么每个结点可以指定以它为根的子树(后面讨论的子树都是这个)。现在我们把标号从1到n的n个minister派驻到这些结点上面(每个结点派驻一人),并规定任一子树中编号最大的minister 为该子树的领导,问你存在多少个不同的领导

解:

引用官方题解:

可以用求概率的思想来解决这个问题。令以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 /*
 2  * Problem: hdu5378  Leader in Tree Land
 3  * Author:  SHJWUDP
 4  * Created Time:  2015/8/12 星期三 20:17:31
 5  * File Name: 1006.cpp
 6  * State: Accepted
 7  * Memo: 概率dp,乘法逆元
 8  */
 9 #include <iostream>
10 #include <cstdio>
11 #include <vector>
12 #include <cstring>
13 #include <algorithm>
14 
15 using namespace std;
16 
17 const int MOD=1e9+7;
18 
19 struct Edge {
20     int u, v;
21 };
22 
23 int n, k;
24 vector<Edge> edges;
25 vector<vector<int> > G;
26 vector<int> siz, inv;    ///siz[i]*inv[i]=1(mod 1e9+7)
27 void init() {
28     edges.clear();
29     G.assign(n+1, vector<int>(0));
30     siz.resize(n+1);
31     inv.resize(n+1);
32 }
33 void addEdge(int u, int v) {
34     edges.push_back((Edge){u, v});
35     G[u].push_back(edges.size()-1);
36 }
37 int pow_mod(long long x, int n, int mod) {
38     long long res=1;
39     while(n) {
40         if(n & 1) res=res*x%mod;
41         x=x*x%mod;
42         n>>=1;
43     }
44     return res;
45 }
46 void dfs(int u, int fa) {
47     siz[u]=1;
48     for(int i : G[u]) {
49         Edge & e=edges[i];
50         if(e.v==fa) continue;
51         dfs(e.v, u);
52         siz[u]+=siz[e.v];
53     }
54 }
55 int main() {
56 #ifndef ONLINE_JUDGE
57     freopen("in", "r", stdin);
58     //freopen("out", "w", stdout);
59 #endif
60     int T, now=0;
61     scanf("%d", &T);
62     while(T--) {
63         scanf("%d%d", &n, &k);
64         init();
65         for(int i=0; i<n-1; i++) {
66             int a, b;
67             scanf("%d%d", &a, &b);
68             addEdge(a, b);
69             addEdge(b, a);
70         }
71         dfs(1, -1);
72         for(int i=1; i<=n; i++) inv[i]=pow_mod(siz[i], MOD-2, MOD);    //求siz[i]的乘法逆元
73         vector<vector<long long> > f(n+1, vector<long long>(n+1, 0));
74         f[0][0]=1;
75         for(int i=1; i<=n; i++) {
76             for(int j=0; j<=k; j++) {
77                 f[i][j]+=f[i-1][j]*(siz[i]-1)%MOD*inv[i]%MOD;
78                 if(j>0)f[i][j]+=f[i-1][j-1]*inv[i]%MOD;
79                 f[i][j]%=MOD;
80             }
81         }
82         long long ans=f[n][k];
83         for(int i=1; i<=n; i++) {
84             ans=(ans*i)%MOD;
85         }
86         printf("Case #%d: ", ++now);
87         printf("%I64d\n", ans);
88     }
89     return 0;
90 }
View Code

 

posted on 2015-08-12 22:41  shjwudp  阅读(213)  评论(0编辑  收藏  举报