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

玄学之门

  • 题目:
  • 分析:
  • 代码:


题目:

传送门


分析:

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


代码:

#include
#include
#include
#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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;
}

你可能感兴趣的:(组合数,快速幂,数论,数论,快速幂,组合数)