组合数取模介绍----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;
}

 

posted @ 2019-04-08 21:15  知道了呀~  阅读(321)  评论(0编辑  收藏  举报