题目链接:hdu 5378 Leader in Tree Land
问题可以理解成N个节点的树,有K个ministers的概率,最后乘上N!。每个节点为ministers的概率即为1 / son(以该节点为根节点的子树包含的节点个数),同样不为ministers的概率为(son-1)/son。所以没有必要考虑树的结构,直接根句子节点的个数转移dp[i][j]
dp[i][j] = dp[i-1][j-1] * 1 / son[u]
dp[i][j] = dp[i-1][j] * (son[u]-1]) / son[u]
取模的部分可以用逆元。
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int mod = 1000000007;
const int maxn = 1005;
int fac[maxn];
int N, K, son[maxn];
ll dp[maxn][maxn];
vector<int> G[maxn];
void dfs (int u, int f) {
son[u] = 1;
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if (v == f)
continue;
dfs(v, u);
son[u] += son[v];
}
}
void init () {
scanf("%d%d", &N, &K);
for (int i = 1; i <= N; i++)
G[i].clear();
int u, v;
for (int i = 1; i < N; i++) {
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, 0);
}
void exgcd (ll a, ll b, ll& d, ll& x, ll&y) {
if (!b)
d = a, x = 1, y = 0;
else {
exgcd(b, a%b, d, y, x);
y -= x * (a/b);
}
}
ll inv (ll a) {
ll d, x, y;
exgcd(a, mod, d, x, y);
return d == 1 ? (x + mod) % mod : -1;
}
int solve () {
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for (int i = 1; i <= N; i++) {
for (int j = 0; j <= K; j++) {
if (dp[i-1][j] == 0)
continue;
dp[i][j] = (dp[i][j] + dp[i-1][j] * (son[i] - 1) % mod * inv(son[i])) % mod;
dp[i][j+1] = (dp[i][j+1] + dp[i-1][j] * inv(son[i])) % mod;
}
}
return dp[N][K] * fac[N] % mod;
}
int main () {
fac[1] = 1;
for (int i = 2; i <= 1000; i++)
fac[i] = 1LL * i * fac[i-1] % mod;
int cas;
scanf("%d", &cas);
for (int kcas = 1; kcas <= cas; kcas++) {
init ();
printf("Case #%d: %d\n", kcas, solve());
}
return 0;
}