51nod1805 小树

题意:输入N,M,(2<=n, m<=1000000)一颗有标号无根树n个节点,有m个叶子节点,问有多少颗满足条件的树

题解:一颗有标号的无根树可以一一对应一个prufer序列,有一个定理:prufer序列中出现数字的次数+1是这个数字标号的度数,那么这里可以知道度数为1的有m个,也就是问恰好有1-n中的n-m种数且长度为n-2的序列有多少个,容斥+组合数

 

#include <bits/stdc++.h>
#define ll long long
#define maxn 1000100
using namespace std;
const ll mod = 1e9+7;
ll fc[maxn], fi[maxn];
ll f(ll a,ll b){
    ll ans = 1;
    while(b){
        if(b&1) ans = ans*a%mod;
        a = a*a%mod;
        b >>= 1;
    }
    return ans;
}
void init(){
    fc[0] = 1;
    for(ll i=1;i<maxn;i++) fc[i] = fc[i-1]*i%mod;
    fi[maxn-1] = f(fc[maxn-1], mod-2);
    for(ll i=maxn-1;i>=1;i--) fi[i-1] = fi[i]*i%mod;
}
ll c(ll n,ll m){
    return fc[n]*fi[m]%mod*fi[n-m]%mod;
}
int main(){
    init();
    ll n, m, ans = 0;
    scanf("%lld%lld", &n, &m);
    if(n == 2) return 0*printf("1\n");
    for(ll i=n-m;i>=1;i--){
        if((n-m-i)&1) ans -= c(n-m, i)*f(i, n-2)%mod;
        else ans += c(n-m, i)*f(i, n-2)%mod;
        ans = (ans+mod)%mod;
    }
    printf("%lld\n", ans*c(n, n-m)%mod);
    return 0;
}

 

posted on 2018-02-02 14:43  2855669158  阅读(127)  评论(0编辑  收藏  举报

导航