zoukankan      html  css  js  c++  java
  • [2015hdu多校联赛补题]hdu5378 Leader in Tree Land

    题目链接: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
    ", ans);
    88     }
    89     return 0;
    90 }
    View Code
  • 相关阅读:
    poj 2411 Mondriaan's Dream 骨牌铺放 状压dp
    zoj 3471 Most Powerful (有向图)最大生成树 状压dp
    poj 2280 Islands and Bridges 哈密尔顿路 状压dp
    hdu 3001 Travelling 经过所有点(最多两次)的最短路径 三进制状压dp
    poj 3311 Hie with the Pie 经过所有点(可重)的最短路径 floyd + 状压dp
    poj 1185 炮兵阵地 状压dp
    poj 3254 Corn Fields 状压dp入门
    loj 6278 6279 数列分块入门 2 3
    VIM记事——大小写转换
    DKIM支持样本上传做检测的网站
  • 原文地址:https://www.cnblogs.com/shjwudp/p/4725795.html
Copyright © 2011-2022 走看看