盧卡斯定理

盧卡斯定理

用途

盧卡斯(\(Lucas\))定理用於求當\(n\)\(m\)較大時,\(C_n^m mod\;p(p爲質數)\)的值。spa

描述

遞歸形式

對於
\[ n,m \in \mathbb{Z},p爲質數 \]

\[ C_n^m mod\;p=C_{n\;mod\;p}^{m\;mod\;p}\cdot C_{n/p}^{m/p} mod\;p \]code

非遞歸形式

對於
\[ n,m \in \mathbb{Z},p爲質數\\ 設m=\prod_{i=0}^{k}m_ip^i,n=\prod_{i=0}^{k}n_ip^i \]

\[ C_n^m mod\;p=\prod_{i=0}^{k}C_{n_i}^{m_i}mod\;p \]遞歸

使用方法

對於比較大的組合數,咱們先利用盧卡斯定理將其拆分,拆分所獲得的每一個較小的組合數則能夠用更簡單的方法求解。對於遞歸形式,拆分出的\(C_{n\;mod\;p}^{m\;mod\;p}\)還原成階乘形式後,因爲\(p\)爲質數且除數與\(p\)互質,咱們能夠考慮運用費馬小定理之類的方法求逆元進行計算。對於非遞歸形式,至關於把\(m\)\(n\)均當作一個\(p\)進制下的數,其每一位也與\(p\)互質,也能夠如此計算。ip

注意邊界條件:當\(m=0\)時,\(C_n^m=1\);當\(n<m\)時,\(C_n^m=0\)。階乘能夠進行預處理減小重複計算。class

代碼

//遞歸
int power(int b,int k)
{
    int base=1;
    while(k)
    {
        if(k&1)
            base=(long long)base*b%p;
        k>>=1;
        b=(long long)b*b%p;
    }
    return base;
}
int inv(int x)
{
    return power(x,p-2);
}
int C(int x,int y)
{
    return (long long)factorial[x]*inv((long long)factorial[y]*factorial[x-y]%p)%p;
}
int Lucas(int x,int y)
{
    if(!y)
        return 1;
    if(x%p<y%p)
        return 0;
    return C(x%p,y%p)*Lucas(x/p,y/p)%p;
}
//非遞歸
int Lucas(int x,int y)
{
    int result=1;
    while(x&&y)
    {
        if(x%p<y%p)
            return 0;
        result=(long long)result*C(x%p,y%p)%p;
        x/=p;
        y/=p;
    }
    return result;
}
相關文章
相關標籤/搜索