zoukankan      html  css  js  c++  java
  • 逆元

    现在目标是求$C_n^m\%p$,p为素数(经典p=1e9+7)

    虽然有$C_n^m=frac{n!}{m!(n-m)!}$,但由于取模的性质对于除法不适用,所以$C_n^m\%p$≠$( frac{n!\%p}{m!\%p*(n-m)!\%p} )\%p$

    所以需要把“除法”转换成“乘法”,才能借助取模的性质在不爆long long的情况下计算组合数。这时候就需要用到“逆元”!

      逆元:对于a和p(a和p互素),若a*b%p≡1,则称b为a%p的逆元。

    那这个逆元有什么用呢?试想一下求$(frac{a}{b})$%p,如果你知道b%p的逆元是c,那么就可以转变成$(frac{a}{b})$%p = a*c%p = (a%p)(c%p)%p

    那怎么求逆元呢?这时候就要引入强大的费马小定理!

      费马小定理:对于a和素数p,满足$a^{p-1}$%p≡1

    接着因为$a^{p-1}$ = $a^{p-2}*a$,所以有$a^{p-2}*a$%p≡1!对比逆元的定义可得,$a^{p-2}$是a的逆元!

    所以问题就转换成求解$a^{p-2}$,即变成求快速幂的问题了(当然这需要满足p为素数)。

    现在总结一下求解$C_n^m\%p$的步骤:

    1. 通过循环,预先算好所有小于max_number的阶乘(%p)的结果,存到fac[max_number]里 (fac[i] = i!%p)
    2. 求m!%p的逆元(即求fac[m]的逆元):根据费马小定理,x%p的逆元为$x^{p-2}$,因此通过快速幂,求解$fac[m]^{p-2}$%p,记为M
    3. 求(n-m)!%p的逆元:同理为求解$fac[n-m]^{p-2}$%p,记为NM
    4. $C_n^m\%p$ = ((fac[n]*M)%p*NM)%p

    用C++实现的代码,输入为n,m,p,要求0<=m<=n<=1e6(否则fac存不下),且gcd(p,n!)=1(即互素),输出为$C_n^m\%p$

    //快速幂求x^n%mod 
    long long pow_mod(long long x, long long n, long long mod) {
        long long res = 1;
        while (n) {
            if (n & 1) res = res * x % mod;
            x = x * x % mod;
            n >>= 1;
        }
        return res;
    }
    long long fac[MAX_NUMBER+5];
    long long n, m, p;
    int main() {
        while (~scanf("%lld %lld %lld", &n, &m, &p)) {        
            //预处理求fac,fac[i] = i!%p 
            fac[0] = 1;
            for (int i = 1; i <= n; i++) {fac[i] = fac[i - 1] * i % p;}
            //组合数 = n!*(m!%p的逆元)*((n-m)!%p的逆元)%p 
            printf("%lld
    ", fac[n] * pow_mod(fac[m], p - 2, p) % p * pow_mod(fac[n - m], p - 2, p) % p);
        }
    }

    另一种求法以后有空再写...

  • 相关阅读:
    Java实现 LeetCode 679 24 点游戏(递归)
    Java实现 LeetCode 678 有效的括号字符串(暴力+思路转换)
    Java实现 LeetCode 678 有效的括号字符串(暴力+思路转换)
    Java实现 LeetCode 678 有效的括号字符串(暴力+思路转换)
    Java实现 LeetCode 677 键值映射(字典树)
    Java实现 LeetCode 677 键值映射(字典树)
    Java实现 LeetCode 677 键值映射(字典树)
    Java实现 LeetCode 676 实现一个魔法字典(暴力)
    PHP empty() 函数
    PHP floatval()、doubleval () 函数
  • 原文地址:https://www.cnblogs.com/liziran/p/6804803.html
Copyright © 2011-2022 走看看