卢卡斯定理总结

卢卡斯定理 Lucas定理是用来求组合数 \(c(n,m) mod\ p\)\(p\) 为素数的值。被用来做大组合数取模。

我们令 \(n = sp + q, m = tp + r\) ,其中 \(q, r < p\) ,那么有:

\[\binom{n}{m} \equiv \binom{sp+q}{tp+r} \equiv \binom{s}{t}\binom{q}{r} (mod\ p) \]

求解大组合数取模时,只需继续对 \(\binom{s}{t}\) 递归调用卢卡斯定理。递归边界为 \(t = 0\)

时间复杂度为 \(O(p\log_p n)\)

卢卡斯定理证明

首先,我们易得 \(\binom{p}{f} \equiv 0 (mod\ p)\) ,其中 \(f > 0, p > f\)

然后,我们又有:

\[\begin{split} (1+x)^n \equiv(1+n)^{sp+q} &\equiv ((1+x)^p)^s \cdot (1+x)^q(mod\ p) \\ &\equiv (1+x^p)^s\cdot (1+x)^q(mod\ p) \\ &\equiv \sum_{i=0}^s \binom{s}{i}x^{i\cdot p} \cdot \sum_{j=0}^{q}x^j (mod\ p) \end{split}\]

【注】这里 \((1+x)^p \equiv (1+x^p)(mod\ p)\) 是因为 \(p\) 是质数,它的组合数 \(\binom{p}{k}\) 不会把 \(p\) 因子消掉,所以一定是 \(p\) 的倍数。

所以我们有:

\[(1+x)^{sp+q} \equiv \sum_{i=0}^s \binom{s}{i}x^{i\cdot p} \cdot \sum_{j=0}^{q}x^j (mod\ p) \]

我们求左边 \((1+x)^{sp+q}\) 中的 \(x^{tp+r}\) 的系数为:\(\binom{sp+q}{tp+r}\)

我们求右边 \((1+x)^{tp+r}\) 的系数为:\(i=t,j=r\) 的系数,即:\(\binom{s}{t}\cdot \binom{q}{r}\)

所以有:

\[\binom{sp+q}{tp+r} \equiv \binom{s}{t}\binom{q}{r} (mod\ p) \]

得证。

题目

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 100005;
ll a[N];
int p, T, n, m;

ll pow(ll y,int z,int p){
    y%=p;ll ans=1;
    for(int i=z;i;i>>=1,y=y*y%p)if(i&1)ans=ans*y%p;
    return ans;
}
ll C(ll n,ll m){
    if(m>n)return 0;
    return ((a[n]*pow(a[m],p-2,p))%p*pow(a[n-m],p-2,p)%p);
}
ll Lucas(ll n,ll m){
    if(!m)return 1;
    return C(n%p,m%p)*Lucas(n/p,m/p)%p;
}
int main(){
    cin >> T;
    while(T--){
        cin >> n >> m >> p;
        a[0]=1;
        for(int i = 1; i <= p; i++) a[i] = (a[i - 1] *  i) % p;
        cout << Lucas(n + m, n) << endl;
    }
}

posted on 2019-08-30 11:28  solvit  阅读(507)  评论(0)    收藏  举报

导航