官方题解:
可以用求概率的思想来解决这个问题。令以i号节点为根的子树为第i棵子树,设这颗子树恰好有sz[i]个点。那么第i个点是第i棵子树最大值的概率为1/sz[i],不是最大值的概率为(sz[i]-1)/sz[i]。现在可以求解恰好有k个最大值的概率。
令dp[i][j]表示考虑编号从1到i的点,其中恰好有j个点是其子树最大值的概率。 很容易得到如下转移方程:dp[i][j]=dp[i-1][j]*(sz[i]-1)/sz[i]+dp[i-1][j-1]/sz[i]。这样dp[n][k]就是所有点中恰好有k个最大值的概率。
题目要求的是方案数,用总数n!乘上概率就是答案。计算的时候用逆元代替上面的分数即可
另外我补充一下边界情况:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 using namespace std; 7 8 typedef long long LL; 9 10 const int maxn = 1000 + 10; 11 const LL MOD = 1000000007; 12 13 LL fac[maxn], invfac[maxn], inv[maxn]; 14 15 inline LL mul_mod(LL a, LL b) { return (a * b) % MOD; } 16 17 LL pow_mod(LL a, LL n) 18 { 19 LL ans = 1, base = a; 20 while(n) 21 { 22 if(n & 1) ans = mul_mod(ans, base); 23 base = mul_mod(base, base); 24 n >>= 1; 25 } 26 return ans; 27 } 28 29 LL inverse(LL a) { return pow_mod(a, MOD - 2); } 30 31 void preprocess() 32 { 33 fac[0] = 1; 34 for(int i = 1; i < maxn; i++) { inv[i] = inverse(i); fac[i] = (fac[i - 1] * i) % MOD; } 35 invfac[maxn - 1] = inverse(fac[maxn - 1]); 36 for(int i = maxn - 2; i >= 0; i--) invfac[i] = mul_mod(invfac[i+1], (i+1)); 37 } 38 39 vector<int> G[maxn]; 40 41 int sz[maxn]; 42 43 void dfs(int u, int fa) 44 { 45 sz[u] = 1; 46 for(int i = 0; i < G[u].size(); i++) 47 { 48 int v = G[u][i]; 49 if(v == fa) continue; 50 dfs(v, u); 51 sz[u] += sz[v]; 52 } 53 } 54 55 LL d[maxn][maxn]; 56 57 int main() 58 { 59 preprocess(); 60 61 int T; scanf("%d", &T); 62 for(int kase = 1; kase <= T; kase++) 63 { 64 int n, k; scanf("%d%d", &n, &k); 65 for(int i = 1; i <= n; i++) G[i].clear(); 66 for(int u, v, i = 1; i < n; i++) 67 { 68 scanf("%d%d", &u, &v); 69 G[u].push_back(v); G[v].push_back(u); 70 } 71 72 dfs(1, 0); 73 d[1][0] = mul_mod(sz[1] - 1, inv[sz[1]]); 74 d[1][1] = inv[sz[1]]; 75 for(int i = 2; i <= n; i++) 76 { 77 d[i][0] = mul_mod(mul_mod(d[i-1][0], sz[i] - 1), inv[sz[i]]); 78 for(int j = 1; j <= min(i, k); j++) 79 { 80 LL t1 = mul_mod(mul_mod(d[i-1][j], sz[i] - 1), inv[sz[i]]); 81 LL t2 = mul_mod(d[i-1][j-1], inv[sz[i]]); 82 d[i][j] = t1 + t2; 83 if(d[i][j] >= MOD) d[i][j] -= MOD; 84 } 85 } 86 87 LL ans = mul_mod(d[n][k], fac[n]); 88 printf("Case #%d: %I64d ", kase, ans); 89 } 90 91 return 0; 92 }