zoukankan      html  css  js  c++  java
  • 2015多校第7场 HDU 5378 Leader in Tree Land 概率DP

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

    题意:一棵n个节点的树。对其节点进行标号(1~n)。求恰好存在k个节点的标号是其节点所在子树的最大值的方案数。

    解法:

    首先,总共有n!中标号方案。而如果求出n个节点中出现k个上述节点的概率p。方案数等于n!* p。
    dp[i][j] 表示钱i个节点有j个上述节点的概率。转移较容易推出。
    dp[i][j] = dp[i-1][j] * (c[i]-1) / c[i] + dp[i-1][j-1] * (1 / c[i]);    c[i] 第i个节点的子树的节点数。

    有除法要处理逆元。

    //HDU 5378
    
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const LL mod = 1e9+7;
    const int maxn = 1010;
    int n, k, edgecnt, head[maxn];
    struct edge{
        int to,next;
    }E[maxn*2];
    void init(){
        edgecnt=0;
        memset(head,-1,sizeof(head));
    }
    void add(int u, int v){
        E[edgecnt].to=v,E[edgecnt].next=head[u],head[u]=edgecnt++;
    }
    int sz[maxn];
    LL inv[maxn], dp[maxn][maxn];
    //dp[i][j]代表前i个点,恰好有j个点是leader的概率
    //dp[i][j] = dp[i-1][j]*(sz[i]-1)/sz[i]+dp[i-1][j-1]/sz[i]
    void dfs(int u, int pre){
        sz[u] = 1;
        for(int i = head[u]; ~i; i=E[i].next){
            int v = E[i].to;
            if(v == pre) continue;
            dfs(v, u);
            sz[u] += sz[v];
        }
    }
    void INIT(){
        inv[1] = 1;
        for(int i = 2; i < maxn; i++) inv[i] = 1LL*(mod-mod/i)*inv[mod%i]%mod;
    }
    
    int main()
    {
        init();
        int T, ks = 0;
        INIT();
        scanf("%d", &T);
        while(T--)
        {
            init();
            scanf("%d %d", &n,&k);
            for(int i=1; i<n; i++){
                int u, v;
                scanf("%d %d", &u,&v);
                add(u, v);
                add(v, u);
            }
            dfs(1, -1);
            memset(dp, 0, sizeof(dp));
            dp[0][0] = 1;
            dp[1][0] = (sz[1]-1)*inv[sz[1]]%mod;
            dp[1][1] = inv[sz[1]];
            for(int i=2; i<=n; i++){
                dp[i][0] = dp[i-1][0]*(sz[i]-1)%mod*inv[sz[i]]%mod;
                for(int j=1; j<=min(i,k); j++){
                    dp[i][j] = ((dp[i-1][j]*(sz[i]-1))%mod*inv[sz[i]]%mod)%mod;
                    dp[i][j] = (dp[i][j] + (dp[i-1][j-1]%mod*inv[sz[i]]%mod)%mod)%mod;
                }
            }
            LL ans = dp[n][k];
    
            for(int i=1; i<=n; i++){
                ans = (ans*i)%mod;
            }
            printf("Case #%d: %lld
    ", ++ks, ans%mod);
        }
        return 0;
    }
    
  • 相关阅读:
    买书问题
    结队开发项目—NABC模型
    《梦断代码》读后感3
    <梦断代码>读后感2
    四则运算3
    数组结对开发
    BICEP单元测试——随机四则运算升级版
    新 四则运算题目 修改
    新 四则运算题目 C++
    新 四则运算题目设计思路
  • 原文地址:https://www.cnblogs.com/spfa/p/7305512.html
Copyright © 2011-2022 走看看