[概率dp] hdu 5378 Leader in Tree Land

来源:互联网 发布:gx8.86编程软怎么安装 编辑:程序博客网 时间:2024/04/28 21:26

题意:

给你一颗以1位根节点的树,我们定义对于每个子树,节点权值最大的权值记为这个子树的权值,为你将1~n放到这个树里

满足最大权值只有k个的组合数是多少。

思路:

我们可以知道以每个节点为子树,且根节点权值最大的概率是多少,不是的概率是多少。

那么其实问题就变成了 我们在n个物品里面,每个物品拿的概率是pi不拿的概率是1-pi

问你拿k个物品的概率是多少

然后最后乘n!就好了。中间计算运用逆元。

代码:

#include"cstdlib"#include"cstring"#include"cmath"#include"cstdio"#include"queue"#include"algorithm"#include"iostream"#include"stack"using namespace std;#define ll __int64#define N 123456vector<int>edge[2234];ll sum[1234],dp[1234][1234];ll in[1234],mod=1000000007LL;ll power(ll a,ll b){    ll ans=1;    while(b)    {        if(b&1) ans=(ans*a)%mod;        a=(a*a)%mod;        b>>=1;    }    return ans;}void dfs(int x,int f){    int ans=1,lit=edge[x].size();    for(int i=0; i<lit; i++)    {        int v=edge[x][i];        if(v==f) continue;        dfs(v,x);        ans+=sum[v];    }    sum[x]=ans;    return ;}int main(){    int t,cas=1;    cin>>t;    for(int i=1; i<=1234; i++) in[i]=power(i,mod-2); //预处理逆元    while(t--)    {        int n,k;        scanf("%d%d",&n,&k);        for(int i=1; i<=n; i++) edge[i].clear();        for(int i=1; i<n; i++)        {            int x,y;            scanf("%d%d",&x,&y);            edge[x].push_back(y);            edge[y].push_back(x);        }        memset(sum,0,sizeof(sum));        dfs(1,1);        memset(dp,0,sizeof(dp));        dp[0][0]=1;        for(int i=1; i<=n; i++)        {            for(int j=0; j<=k; j++)            {                if(j>0) dp[i][j]=(dp[i][j]+dp[i-1][j-1]*in[sum[i]])%mod;                dp[i][j]=(dp[i][j]+(dp[i-1][j]*(sum[i]-1)%mod)*in[sum[i]]%mod)%mod;            }        }        ll ans=1;        for(int i=1; i<=n; i++) ans=(ans*i)%mod;        ans*=dp[n][k];        printf("Case #%d: %I64d\n",cas++,ans%mod);    }    return 0;}



0 0
原创粉丝点击