卢卡斯定理总结

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

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

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

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

时间复杂度为 (O(plog_p n))

卢卡斯定理证明

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

然后,我们又有:

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

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

所以我们有:

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

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

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

所以有:

[inom{sp+q}{tp+r} equiv inom{s}{t}inom{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;
    }
}
原文地址:https://www.cnblogs.com/solvit/p/11434070.html