码迷,mamicode.com
首页 > 其他好文 > 详细

HDU-5378 概率DP

时间:2019-09-27 21:11:35      阅读:78      评论:0      收藏:0      [点我收藏+]

标签:void   div   解法   cin   cto   turn   amp   递推   题意   

题意:给定一棵有n个节点的树,现在要给节点附1~n的权值(各节点权值不能相同),一棵子树的领袖就是子树中权值最大的节点,问有多少种分配方案使得最后有恰好K个领袖。

解法:这道题一看以为是树上的计数问题,想了好久的树形DP没想到,最后看题解才知道解法是概率DP(qwq)。解法还是非常巧妙的,感觉自己现在还没理解到它的精髓。

先求出这棵树以i点位根的子树的结点个数son[i],然后就不用管这棵树了。设dp[i][j]为前i棵子树恰好有j个领袖的概率。

因为问的是方案数,所以随机选,选择没有优劣之分每个点都是等概率的,那么我们可以写出dp方程。

dp[i][j]=(dp[i-1][j]*(son[i]-1)/son[i] , dp[i-1][j-1]*1/son[i] ) 前面代表第i个点就是领袖后面代表第i个点不是领袖。

注意这是个线性递推方程式,此时这里的i是线性的,与树的结构已经没有关系了。

求出dp[n][k]之后,答案就是dp[n][k]*n!  

 

代码要注意因为每次都要除以son[i]所以难免要求逆元,因为状态多达1000^2个所以不先把逆元预处理出来会TLE。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e3+10;
const int P=1e9+7;
int n,k,son[N];
int dp[N][N];
vector<int> G[N];

LL power(LL x,LL p) {
    LL ret=1;
    for (;p;p>>=1) {
        if (p&1) ret=ret*x%P;
        x=x*x%P;
    }
    return ret;
}

void dfs(int x,int fa) {
    son[x]=1;
    for (int i=0;i<G[x].size();i++) {
        int y=G[x][i];
        if (y==fa) continue;
        dfs(y,x);
        son[x]+=son[y];
    }
}

int inv[N];
void prework() {
    for (int i=1;i<=1000;i++) inv[i]=power(i,P-2);
}

int main()
{
    prework();
    int T,cas=0; cin>>T;
    while (T--) {
        scanf("%d%d",&n,&k);
        for (int i=1;i<=n;i++) G[i].clear();
        for (int i=1;i<n;i++) {
            int x,y; scanf("%d%d",&x,&y);
            G[x].push_back(y);
            G[y].push_back(x);
        }
        for (int i=1;i<=n;i++) son[i]=0;
        dfs(1,0);
        
        for (int i=0;i<=n;i++) for (int j=0;j<=n;j++) dp[i][j]=0;
        dp[0][0]=1;
        for (int i=1;i<=n;i++) 
            for (int j=0;j<=min(i,k);j++) {
                if (j<1) dp[i][j]=(LL)dp[i-1][j]*(son[i]-1)%P*inv[son[i]]%P;
                else dp[i][j]=((LL)dp[i-1][j]*(son[i]-1)%P*inv[son[i]]%P+(LL)dp[i-1][j-1]*1*inv[son[i]]%P)%P;
            }
    
        int ans=dp[n][k];
        for (int i=1;i<=n;i++) ans=((LL)ans*i)%P;
        printf("Case #%d: %d\n",++cas,ans);
    }
    return 0;
}

 

HDU-5378 概率DP

标签:void   div   解法   cin   cto   turn   amp   递推   题意   

原文地址:https://www.cnblogs.com/clno1/p/11600144.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!