Luogu3807 【模板】卢卡斯定理
https://www.luogu.com.cn/problem/P3807
卢卡斯定理
用于求解\(n,m\)较大和\(n \ge p\)的情况
结论\(1\):对于\(k \in [1,p-1]\),有\({p \choose k} \equiv 0 (\mod p)\)
证明:
\[
{p \choose k}=\frac{p!}{k!(p-k)!}\\
=\frac{p}{k} \times \frac{(p-1)!}{(k-1)![(p-1)-(k-1)]!}\\
=\frac{p}{k} \times {p-1 \choose k-1}\\
\because p \in prime,k<p\\
\therefore \gcd(k,p)=1\\
\therefore \frac{p}{k} \times {p-1 \choose k-1} \equiv 0 (\mod p)
\]
结论\(2\):\((1+k)^p \equiv k^p+1 (\mod p)\)
证明:
\[(1+k)^p=1+\sum_{i=1}^{p-1} {p \choose i} k^i+k^p \equiv 1+k^p (\mod p)
\]
设\(n=ap+b(0 \le b<p)\),\(m=cp+d(0\le d<p)\)
\[(1+k)^n=(1+k)^{ap} \times (1+k)^b \\
=(1+k^p)^a \times (1+k)^b\\
=(\sum_{i=0}^a {a \choose i}k^{ip}) \times (\sum_{j=0}^b {b \choose j}k^{j})
\]
我们从\(\sum_{i=0}^a {a \choose i}k^{ip}\)中抽取\(k^{cp}\),从\(\sum_{j=0}^b {b \choose j}k^{j}\)中抽取\(k^d\)
得到公式:
\[{n \choose m} (\mod p)=\\
\]
\[{\lfloor \frac{n}{p} \rfloor \choose \lfloor \frac{m}{p} \rfloor } {n \mod p \choose m \mod p}
\]
即卢卡斯定理
\(C++ Code:\)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#define N 200005
#define ll long long
using namespace std;
int T,n,m,p;
ll jc[N],invjc[N];
ll ksm(ll x,ll y)
{
ll ans=1;
while (y)
{
if (y & 1)
ans=ans*x%p;
x=x*x%p;
y >>=1;
}
return ans;
}
#define inv(x) (ksm(x,p-2))
#define C(n,k) (jc[n]*invjc[k]%p*invjc[n-k]%p)
ll Lucas(int n,int m,int p)
{
if (!n||!m)
return 1;
return Lucas(n/p,m/p,p)*C(n%p,m%p)%p;
}
int main()
{
scanf("%d",&T);
while (T --> 0)
{
scanf("%d%d%d",&n,&m,&p);
n+=m;
jc[0]=1;
for (int i=1;i<=n;i++)
jc[i]=jc[i-1]*(ll)i%p;
for (int i=0;i<=n;i++)
invjc[i]=inv(jc[i]);
printf("%lld\n",Lucas(n,m,p));
}
return 0;
}