卢卡斯定理与扩展卢卡斯定理的复健

其实这两个定理没有任何关系,,

 

卢卡斯定理:

前置知识二项式定理

\binom{n}{m}=\binom{n/p}{m/p}*\binom{n\mod p}{m\mod p}(\mod p)

递归计算复杂度plogp。

证明:

n=sp+q,m=tp+r

有费马小定理可得两个式子:

(1+x)^p\equiv (1+x) \mod p

(1+x^p)\equiv (1+x) \mod p

转换一下得到

(1+x)^n

=((1+x)^{p})^s*(1+x)^q

=(1+x^p)^s*(1+x)^q

=\sum_{i=0}^s\binom{s}{i}x^{pi}*\sum_{j=0}^q\binom{q}{j}x^j

而直接把(1+x)^n=(1+x)^{sp+q}二项式展开有

=\sum_{i=0}^{sp+q}\binom{sp+q}{i}x^i

所以\sum_{i=0}^{sp+q}\binom{sp+q}{i}x^i\equiv \sum_{i=0}^s\binom{s}{i}x^{pi}*\sum_{j=0}^q\binom{q}{j}x^j

当左右同取x^{tp+r}的系数时,有

\binom{sp+q}{tp+r}=\binom{s}{t}\binom{q}{r}

得证。

 

扩展卢卡斯定理:

这东西跟卢卡斯定理啥关系也没有,,处理p不为质数的情况。

前置知识:中国剩余定理,扩展欧几里得

根据中国剩余定理,我们大可以算出

\binom{n}{m}\mod p_i^{k_i},的所有结果,然后合并。

而一个组合数可以表达成\frac{n!}{m!(n-m)!}

在只有一个质数的情况下我们大可以直接exgcd找逆元。所以问题实质上只有一个

n!\mod p_i^{k_i}

我们拿22!% 3^2来举例子。

22!=(1*2*3*4*......*22)

按照3^2一组分组,将3倍数拿出来

=(1*2*4*5*7*8)*(10*11*13*14*16*17)*(19*20*22)*(3*6*9*12*15*18*21)

=(1*2*4*5*7*8)*(10*11*13*14*16*17)*(19*20*22)*3^7*(1*2*3*4*5*6*7)

很显然,分出来的组在%p_i^{k_i}意义下是完全相等,一一对应的。所以我们只需要算一组,然后快速幂。

多出来的暴力算。剩下的递归。

那个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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值