求组合数(快速幂求逆元)

求组合数(快速幂求逆元)

费马小定理:

​ 当如果***p是一个质数且整数a不是p的倍数***则有

a p − 1 ≡ 1 a^{p-1} \equiv 1 ap11 (mod p)

乘法逆元定义:

​ 如果整数b,m互质,且对于任意的整数a,如果满嘴b|a,则存在一个整数x满足 a/b ≡ \equiv a * x (mod m)

则称x是b的逆元

b存在逆元的充要条件是b与模数m互质,且m为质数 :

b m − 2 即 为 b 的 逆 元 b^{m-2}即为b的逆元 bm2b

在这里插入图片描述

快速幂就可以求出这个逆元了

求组合数

C a b = a ! ( a − b ) ! b ! C_a^b = \frac{a!}{(a-b)!b!} Cab=(ab)!b!a!

C a b = C a b − 1 + C a − 1 b − 1 C_a^b = C_a^{b-1}+C_{a-1}^{b-1} Cab=Cab1+Ca1b1

两个公式的选取取决于是查找的范围大还是ab的范围大

如果查找的范围很大,ab的范围很小,那么直接预处理所有的C的值即可时间复杂度为N*N(ab的范围)

如果ab的范围很大,则用第一条进行预处理,查询则直接查即可,时间复杂度为 NlogN

因为要mod 1e9 + 7 ,除法的mod不好mod,所以这一步需要用到逆元。

注意!!! 0的阶乘是1

#include<iostream>
using namespace std;

int n;
const int N = 100010,  mod =1e9 + 7;
int fact[N],infact[N];

typedef long long ll;

int qmi(int a ,int  k ,int  m)
{
    int res = 1;
    while(k)
    {
        if(k & 1)
            res  = (ll)res * a % m;
        
        a = (ll)a  * a % m;
        k >>= 1;
    }
    return res;
}
int main()
{
    cin>>n;
    fact[0]= infact[0] = 1;
    //预处理
    for(int i = 1 ;i <= N; i++)
    {
        fact[i] = (ll)fact[i-1] * i % mod;
        infact[i] = (ll)infact[i-1] * qmi(i,mod - 2, mod) % mod;
    }
    
    for(int i = 0 ;i < n ;i ++)
    {
        int x,y;
        cin>>x>>y;
        cout<<(ll)fact[x] * infact[y] % mod * infact[x - y]%mod<<endl; 
    }
    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值