大数组合求逆元的问题

前几天师兄面试碰到一个T厂的算法题,影响是5道算法题,前两题听说很简单,第三题就很难了,下面看一下第三题的内容,具体题目我记不太清楚了,所以我就直接简化题目 
本文参考:https://blog.csdn.net/arrowlll/article/details/52629448

输入描述:

求C(n,m)mod p
0 
  

一、组合定义

大数组合求逆元的问题_第1张图片

阶乘在大二数据结构中就接触过,基本数据类型基本不能满足要求,所以要用一下算法进行简化

二、逆元的定义

      对于正整数 a 和 p,如果有 ax \equiv 1 ( mod p),那么把这个同余方程中 xx 的最小正整数解叫做 aa 模 pp 的逆元。
举个例子:如果ax \% p = 1,那么那么x的最小正整数解就是 a 的逆元。可以进一步转换:(\frac a b \% p)等同于求
(a*(b的逆元)%p),组合数的除法就可以得到解决。

三、费马小定理

    因为在算法竞赛中模数p总是质数,所以可以利用费马小定理 :得到b 的逆元是b^{p-2}

                                                                              b^{p-1} \% p = 1

四、算法实现

        算法实现为参考博客中的实现方法:

  1. 求取1到n的阶乘对 mod 取模的结果存入数组 JC[] 中;
  2. 求取 C(n,r) 时, “费马小定理+快速幂”求 JC[r]的逆元存入临时变量 x_1 ;
  3. 然后计算JC[n] * x_1 \% mod存入临时变量 x_2;(x_2 即为 \frac {n!} {r!} \% mod的值)
  4. 求取JC[n - r] 的逆元存入临时变量x_3
  5. 则可以得到C(n, r) = {x_2} * {x_3} \% mod
typedef long long LL;
const LL maxn(1000005), mod(1e9 + 7);
LL Jc[maxn];

void calJc()    //求maxn以内的数的阶乘
{
    Jc[0] = Jc[1] = 1;
    for(LL i = 2; i < maxn; i++)
        Jc[i] = Jc[i - 1] * i % mod;
}

//费马小定理求逆元
LL pow(LL a, LL n, LL p)    //快速幂 a^n % p
{
    LL ans = 1;
    while(n)
    {
        if(n & 1) ans = ans * a % p;
        a = a * a % p;
        n >>= 1;
    }
    return ans;
}

LL niYuan(LL a, LL b)   //费马小定理求逆元
{
    return pow(a, b - 2, b);
}

LL C(LL a, LL b)    //计算C(a, b)
{
    return Jc[a] * niYuan(Jc[b], mod) % mod
        * niYuan(Jc[a - b], mod) % mod;
}


 

你可能感兴趣的:(试题)