Lucas(盧卡斯)定理


Lucas定理,是用來快速求解一個組合數對於一個數(保證這一個數是質數)的模。
那么,我們先來看Lucas定理的求解式:
\(\binom{n}{m}\%p\)\(p\)是質數)
這樣的一個式子,在\(n,m\leq 10^9\)的時候很容易炸掉,那么我們就要對它利用\(p\)進行化簡求值 。
那么,我們可以將\(n,m\)用另一種形式處理(可以考慮成將\(n,m\)\(p\)進制表示)
\(n=n_k\cdot p^k + n_{k-1}\cdot p^{k-1} + \cdots + n_1\cdot p + n_0\)
\(m=m_k\cdot p^k + m_{k-1}\cdot p^{k-1} + \cdots + m_1\cdot p + m_0\)
那么,\(\binom{n}{m}\equiv\binom{n_k}{m_k}\binom{n_{k-1}}{m_{k-1}}\cdots\binom{n_0}{m_0}\ (mod\ p)\)
是不是看起來很累啊,我們換一種方法\(\binom{n}{m}\equiv\prod_{i=0}^{k}\binom{n_i}{m_i} \ (mod\ p)\)
(p是質數就不寫了哈,反正所有的p都是質數)
我們接下來證明:(不喜歡看這一段的同學直接看代碼啦)
\(n=a\cdot p+b,m=c\cdot p+d\)
\(\therefore a=\left \lfloor \frac{n}{p} \right \rfloor,b=\left \lfloor \frac{m}{p} \right \rfloor\)
引理1:$(1+x)^p \equiv 1+x^p \pmod{p} $
證明:
$(1+x)^p \equiv 1+x \pmod{p} $
\(x^p \equiv x \pmod{p}\)
\(1+x^p \equiv 1+x \pmod{p}\)
\(\therefore (1+x)^p \equiv 1+x^p \pmod{p}\)
證畢
\((1+x)^n=(1+x)^{\left \lfloor \frac{n}{p} \right \rfloor \cdot p}\cdot (1+x)^b \equiv (1+x^p)^{\left \lfloor \frac{n}{p} \right \rfloor}\cdot (1+x)^b\)
此處引入二項式定理:\((1+x)^n=\sum_{i=0}^{n}\binom{n}{i}\cdot x^i\)
\(\therefore (1+x^p)^{\left \lfloor \frac{n}{p} \right \rfloor}\cdot (1+x)^b=\sum_{i=0}^{a}\binom{a}{i}x^{p\cdot i}\cdot \sum_{j=0}^{b}\binom{b}{j}x^j\)
\((1+x)^n=\sum_{m=0}^{n}\binom{n}{m}x^m\)
\(\sum_{i=0}^{a}\binom{a}{i}x^{p\cdot i}\cdot \sum_{j=0}^{b}\binom{b}{j}x^j=\sum_{pi+j \leq m且j<p}\binom{a}{i}\binom{b}{j}x^{pi+j}\)
\(\because pi+j=m\)
\(\therefore \binom{a}{i}\binom{b}{j}=\binom{n}{m}\)
接下來迭代證明即可。

那么代碼實現也十分簡單。
【模板】盧卡斯定理
板子題,直接上板子:

#include <cstdio>
#define Maxn 100000
int n,m,p;
int inv[Maxn+5];
int a[Maxn+5];
int ksm(int x,int y){
    int ans=1;
    while(y){
        if(y&1){
            ans=(int)((long long)ans*x%p);
        }
        y>>=1;
        x=(int)((long long)x*x%p);
    }
    return ans;
}//求逆元
int C(int x,int y){
    if(y>x){
        return 0;
    }
    return (int)(1ll*a[x]%p*ksm(a[y],p-2)%p*ksm(a[x-y],p-2)%p);
}//求組合數
int lucas(int x,int y){
    if(y==0){
        return 1;
    }
    return (int)(lucas(x/p,y/p)*1ll*C(x%p,y%p)%p);
}//lucas,用遞歸實現極為簡單
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&n,&m,&p);
        a[0]=1;
        for(int i=1;i<=p;i++){
            a[i]=(int)(a[i-1]*1ll*i%p);
        }//預處理
        printf("%d\n",lucas(n+m,n));
    }
    return 0;
}

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com