HDU 5378 (概率dp)

Leader in Tree Land

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 626    Accepted Submission(s): 283


Problem Description
Tree land has  n  cities, connected by  n1  roads. You can go to any city from any city. In other words, this land is a tree. The city numbered one is the root of this tree.

There are  n  ministers numbered from  1  to  n . You will send them to  n  cities, one city with one minister. 

Since this is a rooted tree, each city is a root of a subtree and there are  n  subtrees. The leader of a subtree is the minister with maximal number in this subtree. As you can see, one minister can be the leader of several subtrees. 

One day all the leaders attend a meet, you find that there are exactly  k  ministers. You want to know how many ways to send  n  ministers to each city so that there are  k ministers attend the meet.

Give your answer mod  1000000007 .
 

Input
Multiple test cases. In the first line there is an integer  T , indicating the number of test cases. For each test case, first line contains two numbers  n,k . Next  n1  line describe the roads of tree land.

T=10,1n1000,1kn
 

Output
For each test case, output one line. The output format is Case # x ans x  is the case number,starting from  1 .
 

Sample Input
  
  
2 3 2 1 2 1 3 10 8 2 1 3 2 4 1 5 3 6 1 7 3 8 7 9 7 10 6
 

Sample Output
  
  
Case #1: 4 Case #2: 316512
 


题意:1-n随机分配给每一个节点,子树的值表示为子树中的节点的最大值.问

所有的子树值有k种的方案数.

每一个节点为根的子树中自身为最大值的概率是1/size(i).然后用f[i][j]表示为

前i个节点中有j种最大值的概率,转移方程就很简单了.因为要避免浮点数,概率

用逆元来搞.

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
#define maxn 1111
#define maxm maxn*2
#define mod 1000000007

struct node {
    int v, next;
}edge[maxn];
int head[maxn], n, k, cnt;
long long dp[maxn];
long long rev[maxn];
long long f[maxn][maxn];

void add_edge (int u, int v) {
    edge[cnt].v = v, edge[cnt].next = head[u], head[u] = cnt++;
}

void dfs (int u, int fa) {
    dp[u] = 1;
    for (int i = head[u]; i != -1; i = edge[i].next) {
        int v = edge[i].v;
        if (v == fa)
            continue;
        dfs (v, u);
        dp[u] += dp[v];
    }
}

long long cal (long long num) {
    return (num%mod+mod)%mod;
}

long long solve () {
    for (int i = 1; i <= n; i++) dp[i] = rev[dp[i]]%mod;
    memset (f, 0, sizeof f);
    f[1][1] = dp[1];
    f[1][0] = cal (1-dp[1]);
    for (int i = 2; i <= n; i++) {
        for (int j = 0; j <= k; j++) {
            f[i][j] += f[i-1][j]*cal (1-dp[i])%mod;
            if (j)
                f[i][j] += f[i-1][j-1]*dp[i]%mod;
            f[i][j] %= mod;
        }
    }
    long long ans = 1;
    for (int i = 2; i <= n; i++)
        ans *= i, ans %= mod;
    return (ans*f[n][k] % mod);
}

void init() {  //预处理逆元
    rev[1] = 1;
    for (int i = 2; i <= 1000; i++){
        rev[i] = (long long)(mod - mod/i) * rev[mod % i] % mod;
    }
}

int main () {
    //freopen ("in.txt", "r", stdin);
    init ();
    int t, kase = 0;
    cin >> t;
    while (t--) {
        cin >> n >> k;
        memset (head, -1, sizeof head);
        cnt = 0;
        printf ("Case #%d: ", ++kase);
        for (int i = 1; i < n; i++) {
            int u, v;
            scanf ("%d%d", &u, &v);
            add_edge (u, v);
            add_edge (v, u);
        }
        dfs (1, 0);
        printf ("%lld\n", solve ());
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值