• 组合数取模介绍----Lucas定理介绍


    转载https://www.cnblogs.com/fzl194/p/9095177.html

    组合数取模方法总结(Lucas定理介绍)

    1.当n,m都很小的时候可以利用杨辉三角直接求。 
    C(n,m)=C(n-1,m)+C(n-1,m-1);

    const int maxn = 1e5 + 10;
    ll fac[maxn];//阶乘打表
    void init(ll p)//此处的p应该小于1e5,这样Lucas定理才适用
    {
        fac[0] = 1;
        for(int i = 1; i <= p; i++)
            fac[i] = fac[i - 1] * i % p;
    }
    ll pow(ll a, ll b, ll m)
    {
        ll ans = 1;
        a %= m;
        while(b)
        {
            if(b & 1)
                ans = (ans % m) * (a % m) % m;
            b /= 2;
            a = (a % m) * (a % m) % m;
        }
        ans %= m;
        return ans;
    }
    ll niyuan(ll x, ll p)//x关于p的逆元,p为素数
    {
        return pow(x, p - 2, p);
    }
    ll C(ll n, ll m, ll p)//组合数C(n, m) % p
    {
        if(m > n)
            return 0;
        return fac[n] * niyuan(fac[m] * fac[n - m], p) % p;
    }
    ll Lucas(ll n, ll m, ll p)
    {
        if(m == 0)
            return 1;
        return C(n % p, m % p, p) * Lucas(n / p, m / p, p) % p;
    }

    2、n和m较大,但是p为素数的时候

    Lucas定理是用来求 c(n,m) mod p,p为素数的值

    C(n,m)%p=C(n/p,m/p)*C(n%p,m%p)%p

    也就是Lucas(n,m)%p=Lucas(n/p,m/p)*C(n%p,m%p)%p

    求上式的时候,Lucas递归出口为m=0时返回1

    求C(n%p, m%p)%p的时候,此处写成C(n, m)%p(p是素数,n和m均小于p)

    C(n, m)%p = n! / (m ! * (n - m )!) % p = n! * mod_inverse[m! * (n - m)!, p] % p

    由于p是素数,有费马小定理可知,m! * (n - m)! 关于p的逆元就是m! * (n - m)!的p-2次方。

    p较小的时候预处理出1-p内所有阶乘%p的值,然后用快速幂求出逆元,就可以求出解。p较大的时候只能逐项求出分母和分子模上p的值,然后通过快速幂求逆元求解。

                          n! 
        C(n,r) = --------------------
                       r!∗(n−r)!
    ll pow(ll a, ll b, ll m)
    {
        ll ans = 1;
        a %= m;
        while(b)
        {
            if(b & 1)ans = (ans % m) * (a % m) % m;
            b /= 2;
            a = (a % m) * (a % m) % m;
        }
        ans %= m;
        return ans;
    }
    ll niyuan(ll x, ll p)//x关于p的逆元,p为素数
    {
        return pow(x, p - 2, p);
    }
    ll C(ll n, ll m, ll p)//组合数C(n, m) % p
    {
        if(m > n)
            return 0;
        ll up = 1, down = 1;//分子分母;
        for(int i = n - m + 1; i <= n; i++)
            up = up * i % p;
        for(int i = 1; i <= m; i++)
            down = down * i % p;
        return up * niyuan(down, p) % p;
    }
    ll Lucas(ll n, ll m, ll p)
    {
        if(m == 0)
            return 1;
        return C(n % p, m % p, p) * Lucas(n / p, m / p, p) % p;
    }
  • 相关阅读:
    iOS controller 和 window 图层
    iOS CGAffineTransform 仿射变换
    iOS UIButton的UIEdgeInsets
    iOS UI的动态布局
    iOS 栅格动态布局
    iOS 系统键盘几个类型
    iOS 金融类高精度处理
    Sublime Text (崇高文本)
    iOS 静态库——制作bundle
    iOS 静态库——制作Framework
  • 原文地址:https://www.cnblogs.com/-citywall123/p/10673451.html
Copyright © 2020-2023  润新知