其实这两个定理没有任何关系,,
卢卡斯定理:
前置知识二项式定理
递归计算复杂度plogp。
证明:
令
有费马小定理可得两个式子:
转换一下得到
而直接把二项式展开有
所以
当左右同取的系数时,有
得证。
扩展卢卡斯定理:
这东西跟卢卡斯定理啥关系也没有,,处理p不为质数的情况。
前置知识:中国剩余定理,扩展欧几里得
根据中国剩余定理,我们大可以算出
,的所有结果,然后合并。
而一个组合数可以表达成
在只有一个质数的情况下我们大可以直接exgcd找逆元。所以问题实质上只有一个
求
我们拿22!% 3^2来举例子。
按照3^2一组分组,将3倍数拿出来
很显然,分出来的组在%意义下是完全相等,一一对应的。所以我们只需要算一组,然后快速幂。
多出来的暴力算。剩下的递归。
那个3的幂次方不用算,只需要在外面手玩一下就可以算出来。
然后答案自然是a*(b的逆元)*(c的逆元)
然后合并。
然后输出。完了
#include<bits/stdc++.h>
using namespace std;
#define in read()
#define int long long
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;
ch=getchar();
}return cnt*f;
}
void exgcd(int a,int b,int &x,int &y){
if(!b){
x=1,y=0;return;
}exgcd(b,a%b,y,x);y-=a/b*x;
}
int ksm(int a,int b,int mod){
int sum=1;while(b){
if(b&1)sum=sum*a%mod;a=a*a%mod;b>>=1;
}return sum;
}
int calc(int n,int pi,int pk){
if(!n)return 1;int sum=1;
if(n/pk){
for(int i=2;i<=pk;i++){
if(i%pi)sum=sum*i%pk;
}
sum=ksm(sum,n/pk,pk);
}
for(int i=2;i<=n%pk;i++)if(i%pi)sum=sum*i%pk;
return sum*calc(n/pi,pi,pk)%pk;
}int p;
int inv(int a,int b){
int x,y;exgcd(a,b,x,y);
x=(x%b+b)%b;
if(!x)return b;
return x;
}
int C(int n,int m,int pi,int pk){
int a=calc(n,pi,pk),b=calc(m,pi,pk),c=calc(n-m,pi,pk);
int k=0;
for(int i=n;i;i/=pi)k+=i/pi;
for(int i=m;i;i/=pi)k-=i/pi;
for(int i=n-m;i;i/=pi)k-=i/pi;
int ans=a*inv(b,pk)%pk*inv(c,pk)%pk*ksm(pi,k,pk)%pk;
ans=(ans*(p/pk)%p*inv(p/pk,pk))%p;
return ans;
}
int n,m;
signed main(){
n=in;m=in;p=in;
int x=p;int ans=0;
for(int i=2;i<=p;i++){
if(x%i==0){
int pi=i,pk=1;
while(x%i==0)pk*=i,x/=i;
ans=(ans+C(n,m,pi,pk))%p;
}
}cout<<ans;
return 0;
}