牛客网:树(乘法逆元求组合数)

链接:https://ac.nowcoder.com/acm/problem/13611
来源:牛客网
 

题目描述

shy有一颗树,树有n个结点。有k种不同颜色的染料给树染色。一个染色方案是合法的,当且仅当对于所有相同颜色的点对(x,y),x到y的路径上的所有点的颜色都要与x和y相同。请统计方案数。

输入描述:

第一行两个整数n,k代表点数和颜色数;
接下来n-1行,每行两个整数x,y表示x与y之间存在一条边;

输出描述:

输出一个整数表示方案数(mod 1e9+7)。

示例1

输入

4 3
1 2
2 3
2 4

输出

39

备注:

对于30%的数据,n≤10, k≤3;
对于100%的数据,n,k≤300。

思路:假的图论题,本质上是个数论题,我们发现颜色相同的点必须要构成一个连通块才是一个合法的染色方案,因此本题转化为将一个树拆成不同连通块的方案数,由于树中有n-1条边,若我们将树拆分成i个连通块,则方案数为C{n-1,i-1},因为颜色数为k,因此我们需要从k个颜色中选择i个颜色给这i个连通块染色,并且这里是讲究顺序的,所以i个连通块的方案数为:C{n-1,i-1}*A{k,i}

#include<vector>
#include<stdio.h>
#include<algorithm>
using namespace std;
#define maxn 505
#define ll long long
#define mod 1000000007
ll n,k,ans,inv[maxn],fac[maxn];
ll q(ll x,ll y){
    x=x%mod;
    ll res=1;
    while(y){
        if(y%2)
            res=res*x%mod;
        x=x*x%mod;
        y/=2;
    }
    return res;
}
ll C(ll x,ll y){
    return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
ll A(ll x,ll y){
    return fac[x]*inv[x-y]%mod;
}
int main(void){
    scanf("%d%d",&n,&k);
    inv[0]=fac[0]=1;
    for(int i=1;i<maxn;i++){
        fac[i]=(fac[i-1]*i)%mod;
        inv[i]=q(fac[i],mod-2);
    }
    for(ll i=1;i<=k && i<=n;i++)
        ans=(ans+C(n-1,i-1)*A(k,i)%mod)%mod;
    printf("%d\n",ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值