卢卡斯定理总结
卢卡斯定理 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;
}
}
浙公网安备 33010602011771号