题目链接:点我点我点我
题目大意:
题目较短,但第一次理解起来可能有点绕脑。最后要求的是不同的旅游方案数,也就是不同路线选取的方案数。
解题思路:
一开始以为是图论,想了一下好像无从下口,看了一下题解原来是有规律可循,当
m
=
=
1
m==1
m==1时答案为
1
1
1,当
m
>
1
m>1
m>1时就可以用
m
−
1
m-1
m−1条边将整个图(连通的)分成
m
m
m个区域,恰好对应题目中的
m
m
m次旅游,也就是说每次旅游选取这
m
m
m个区域里的一个,那么很显然结果我们就要乘以这个
m
m
m的全排列,即旅游的顺序不同。
然后考虑的是怎么选取这
m
−
1
m-1
m−1条边,就是从
n
−
1
n-1
n−1条边中任意选取,也就是
C
(
n
−
1
,
m
−
1
)
C(n-1,m-1)
C(n−1,m−1),求个组合数。
最后答案即为
C
(
n
−
1
,
m
−
1
)
C(n-1,m-1)
C(n−1,m−1)
∗
*
∗
m
!
m!
m!
代码思路:
看到数据范围, m o d mod mod 为 1 e 9 + 7 1e9+7 1e9+7,用逆元求组合数即可。
核心:对题目的理解,算得上是一道读题题吧,前提是会一点数论的知识。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1 << 20;
const int mod = 1000000007;
int t, n, m, ta, tb;
ll c[maxn];
ll PowerMod(ll a, ll b, ll c) { //快速幂
ll ans = 1;
a = a % c;
while (b>0) {
if (b % 2 == 1)
ans = (ans * a) % c;
b = b / 2;
a = (a * a) % c;
}
return ans;
}
void init() { //先打出阶乘,节省时间
c[1] = 1;
for (int i = 2; i <= maxn; i++) {
c[i] = c[i - 1] * i%mod;
}
}
ll C(ll n, ll m) { //逆元求组合数
return c[n] * PowerMod(c[m] * c[n - m] % mod, mod - 2, mod) % mod;
}
int main(void) {
scanf("%d", &t);
init();
while (t-- >0 ) {
scanf("%d%d", &n, &m);
for (int i = 0; i < n - 1; i++)
scanf("%d%d",&ta,&tb);
if (m == 1) {
printf("1\n");
continue;
}
ll ans = C(n - 1, m - 1);
ans = (ans*c[m]) % mod;
printf("%lld\n", ans);
}
}