zoukankan      html  css  js  c++  java
  • 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
    ", kase, ans);
    89     }
    90 
    91     return 0;
    92 }
    代码君
  • 相关阅读:
    神仙题1.0
    一些小技巧(持续更新。。)
    模板(持续更新中。。)
    「CTS2019 | CTSC2019」氪金手游(容斥+概率计数)
    Emacs配置
    AGC034E Complete Compres(dp)
    「清华集训 2017」榕树之心(换根dp)
    [NOI2018]冒泡排序 (卡特兰数)
    「清华集训 2017」小 Y 和二叉树 (贪心)
    「雅礼集训 2018 Day1」图 (dp套dp)
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4730106.html
Copyright © 2011-2022 走看看