当前位置: 代码迷 >> 综合 >> 牛客国庆集训派对Day3___H Travel —— 连通 + 组合数
  详细解决方案

牛客国庆集训派对Day3___H Travel —— 连通 + 组合数

热度:94   发布时间:2024-01-09 11:18:27.0

题目链接:点我点我点我

题目大意:

    题目较短,但第一次理解起来可能有点绕脑。最后要求的是不同的旅游方案数,也就是不同路线选取的方案数。

解题思路:

    一开始以为是图论,想了一下好像无从下口,看了一下题解原来是有规律可循,当 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) Cn?1m?1,求个组合数。
    最后答案即为 C ( n ? 1 , m ? 1 ) C(n-1,m-1) Cn?1m?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);}
}