牛客国庆集训派对Day3 H-Travel

版权声明:喜欢请点个大拇指,感谢各位dalao。弱弱说下,转载要出处呦 https://blog.csdn.net/qq_35786326/article/details/82946525


题目:

传送门


分析:

我们以 m m 的两种情况进行分析:
m = 1 m=1 时:果断输出 1 1
m > 1 m>1 时:我们可以用 m 1 m-1 条边,将这 n n 个点组成的图划分为 m m 个部分,那么这样的话我们就考虑将这 m m 个部分进行排列,也就是 m m 的全排列 m ! →m!
而我们一共有 n 1 n-1 条边,要选出 m 1 m-1 条,即求组合: C m 1 n 1 C_{m-1}^{n-1}
当然这样还是只能得到部分分,因为 C m 1 n 1 C_{m-1}^{n-1} 实在太大了,需要边运算边模,但除法并不具有这样的性质,故我们要将其转化为乘法,我们知道除以一个数,等于乘以这个数的乘法逆元,而再根据费马小定理可以知道一个数 ( x ) (x) 的乘法逆元 ( y ) (y)
= x 2 =x^{模数-2}
而对于上述式子,可以通过快速幂迅速求解


代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring> 
#include<cstdlib>
#include<algorithm>
#include<set>
#include<queue>
#include<vector>
#include<map>
#include<list>
#include<ctime>
#include<iomanip>
#include<string>
#include<bitset>
#include<deque>
#include<set>
#define LL long long
const int h=1 << 20;
#define ch cheap
#define XJQ (int)1000000007
using namespace std;
inline LL read() {
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
}
LL n,m;
LL f[(int)1e5+5];
void fac()
{
    f[1]=1;
    for(int i=2;i<=n;i++) f[i]=(LL)f[i-1]*i%XJQ;
    return;
}
LL gd(LL x,LL y)
{
    LL ans=1;
    while(y)
    {
        if(y&1) ans=ans*x%XJQ;
        y/=2;
        x=x*x%XJQ;
    }
    return ans;
}
LL c()
{
    return f[n-1]*gd(f[m-1]*f[n-m]%XJQ,XJQ-2)%XJQ;
}
int main()
{
    LL t=read();
    LL x;
    while(t--)
    {
        n=read(),m=read();
  	    fac();
        for(int i=0;i<2*n-2;i++) x=read();
        if(m==1) {printf("1\n");continue;}
        printf("%lld\n",(c())*f[m]%XJQ);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35786326/article/details/82946525
今日推荐