【学习笔记】卢卡斯定理(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} \]

posted @ 2025-04-16 17:01  tyh_27  阅读(8)  评论(0)    收藏  举报  来源