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

3 篇文章 0 订阅
2 篇文章 0 订阅


题目:

传送门


分析:

我们以 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<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;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值