【学习笔记】卢卡斯定理(Lucas)
卢卡斯定理(Lucas)
题目:P3807-洛谷
题面
给定整数 \(n,m,p\) 的值,求出 \(\binom{n+m}{n} \bmod p\) 的值,且保证 \(p\) 为质数。
做法
Step 0:
卢卡斯定理:
\[\binom{n}{m}\equiv \binom{\lfloor{\frac{n}{p}}\rfloor}{\lfloor{\frac{m}{p}}\rfloor}\times \binom{n\bmod p}{m\bmod p} \pmod p
\]
证明详见 oi-wiki 卢卡斯定理
可以当作一个结论记。
Step 1:
可以先预处理出所有的 \(i \in [1,p)\), \(i! \bmod p\) 以及 \((i!)^{-1} \bmod p\) 的值。具体求法见 逆元。
之后,我们可以直接求出\(\binom{n\ \bmod \ p}{m\ \bmod \ p} \pmod p\) 的值,只需递归求出 \(\binom{\lfloor{\frac{n}{p}}\rfloor}{\lfloor{\frac{m}{p}}\rfloor}\) 的值即可,边界为其中有一项的值为 \(0\)。
**注:若 \(n \bmod p > m \bmod p\),则它的值为 \(0\)。
Code
#include<bits/stdc++.h>
#define IOS cin.tie(0),cout.tie(0),ios::sync_with_stdio(0)
#define mod 998244353
#define ll long long
#define db double
#define pb push_back
#define MS(x,y) memset(x,y,sizeof x)
using namespace std;
const int N=2e5+5,M=1e5+5;
const ll INF=1ll<<60;
ll n,m,p,k[N],u[N];
void exgcd(ll a,ll b,ll &x,ll &y){
if(!b) x=1,y=0;
else exgcd(b,a%b,y,x),y-=a/b*x;
}
ll calc(ll x,ll y){
return k[x]*u[y]%p*u[(x-y+p)%p]%p;
}
ll Lucas(ll x,ll y){
if(!x || !y) return 1;
ll xx=x%p,yy=y%p;
if(xx<yy) return 0;
return calc(xx,yy)*Lucas(x/p,y/p)%p;
}
void solve(){
cin>>n>>m>>p;
for(int i=1;i<=p-1;i++) k[i]=k[i-1]*i%p;
ll temp=0;
exgcd(k[p-1],p,u[p-1],temp);
u[p-1]=(u[p-1]%p+p)%p;
for(int i=p-2;i>=1;i--) u[i]=u[i+1]*(i+1)%p;
cout<<Lucas(n+m,n)<<"\n";
return ;
}
int main(){
IOS;int T;
cin>>T;
k[0]=u[0]=1;
while(T--) solve();
return 0;
}
\[\mathbb{END}
\]

浙公网安备 33010602011771号