思路:一棵树,从一个点到另一个点只有一条路,这样经过的点就不会存在于其他路径上,所以这个题目其实就是让我们求,n个点,分成 i(1~n)份,每一份可以从k种染料中选一个进行染色,问有多少种方案。能想到是数论题就已经成功一半了。
先看可以有多少种分法:分成两份就需要砍一个边,三份两个边,n个点就有n-1条边,砍成i份就需要砍 i-1 个边,三个点分成两份,有多少种分法?1为根节点: 12 3; 13 2 吧,这个公式应该就呼之欲出了:n个点分成i份有多少种分法: C n − 1 i − 1 C_{n-1}^{i-1} Cn−1i−1
再看有k种染料,需要给i堆节点染色,有多少种染法?有顺序要求的话: A k i A_{k}^{i} Aki
所以题目要求的是以上两个步骤同时满足就需要相乘嘛:n个点分成 i 份,每份需要从k种染料中选择一种染色 有多少种情况? C n − 1 i − 1 ∗ A k i C_{n-1}^{i-1}*A_{k}^{i} Cn−1i−1∗Aki 那么 i 是由 1~n 的,但是 n 比 k 大的情况,这时候在i 也比 k大的时候 染料就不够分了,所以遍历就需要 1 ~ min(n,k) 就好了 公式就是 ∑ i = 1 m i n ( n , k ) C n − 1 i − 1 ∗ A k i \sum_{i=1}^{min(n,k)}C_{n-1}^{i-1}*A_{k}^{i} ∑i=1min(n,k)Cn−1i−1∗Aki
因为这个公式里面会涉及除法,并且需要取模,需要用一下逆元。
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
int n, k;
long long pre[305];
long long qpow(long long x, long long n) {
long long res = 1;
for (; n; n >>= 1, x = x * x % mod)
if (n & 1) res = res * x % mod;
return res;
}
long long C(long long x, long long y) {
return pre[x] * qpow(pre[y]*pre[x-y]%mod, mod-2) % mod;
}
int main() {
scanf("%d %d", &n, &k);
pre[0] = pre[1] = 1;
for(int i = 2;i <= n; i++) pre[i] = i*pre[i-1]%mod;
long long ans = 0;
for(int i = 1;i <= min(n, k); i++) {
ans = (ans+ C(n-1, i-1) * C(k, i) % mod * pre[i] % mod)%mod;
}
printf("%lld\n", ans);
}