链接: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;
}