考虑树上的每条边对答案的贡献
--- x ----y ---
若 x 左边有 a2 个点,y 的右边有 a3 个点
那么改边对答案的贡献为 C(n, k) - C(a2, k) - C(a3, k)
快速幂求逆元计算组合数
注意:计算C(n, m)时, 若 m > n 返回 0
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #define gc getchar() #define ULL unsigned long long #define LL long long inline int read() { int x = 0; char c = gc; while(c < '0' || c > '9') c = gc; while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc; return x; } const int N = 1e5 + 10, Mod = 1e9 + 7; int head[N], cnt; struct Node {int u, v, nxt;} G[N << 1]; int size[N], deep[N]; int n, k; ULL fac[N]; inline void Add(int u, int v) {G[++ cnt].v = v; G[cnt].nxt = head[u]; head[u] = cnt;} void Dfs(int u, int fa, int dep) { size[u] = 1, deep[u] = dep; for(int i = head[u]; ~ i; i = G[i].nxt) { int v = G[i].v; if(v == fa) continue; Dfs(v, u, dep + 1); size[u] += size[v]; } } ULL Ksm(ULL a, ULL b) { ULL ret = 1; while(b) { if(b & 1) ret = (ret * a) % Mod; a = (a * a) % Mod; b >>= 1; } return ret; } Node E[N]; inline ULL C(int n_, int m_) { if(m_ > n_) return 0; ULL x = (fac[m_] * fac[n_ - m_]) % Mod; return (ULL) (fac[n_] * Ksm(x, Mod - 2)) % Mod; } int main() { n = read(), k = read(); fac[1] = fac[0] = 1; for(int i = 1; i <= n; i ++) fac[i] = (fac[i - 1] * i) % Mod; for(int i = 1; i <= n; i ++) head[i] = -1; for(int i = 1; i < n; i ++) { int u = read(), v = read(); Add(u, v), Add(v, u); E[i].u = u, E[i].v = v; } Dfs(1, 0, 1); LL a1 = C(n, k); LL Answer = 0; for(int i = 1; i < n; i ++) { int x = E[i].u, y = E[i].v; if(deep[x] < deep[y]) std:: swap(x, y); int siz1 = size[x], siz2 = n - siz1; LL a2 = C(siz1, k), a3 = C(siz2, k); Answer = (Answer + (a1 - a2 - a3) % Mod) % Mod; } while(Answer < 0) Answer += Mod; std:: cout << Answer; return 0; }