51nod 1677

考虑树上的每条边对答案的贡献
--- 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;
}

猜你喜欢

转载自www.cnblogs.com/shandongs1/p/9462340.html