扩展卢卡斯学习笔记
扩展卢卡斯学习笔记
用途
求 \({\mathrm{C}}_n^m \bmod{p}\)
其中 \(p\) 不一定是质数。
求法
首先将 \(p\) 进行质因数分解,分解为 \(p_1^{a_1}p_2^{a_2} \cdots p_k^{a_k}\) 的形式。
分别求出 \({\mathrm{C}}_n^m \bmod{p_i^{a_i}}\) 的答案用 \(CRT\) 合并即可。
因为 \(p_i^{a_i}\) 不一定是质数,所以不能直接去算 \(m!\) 和 \((n-m)!\) 的逆元,因为这个数有可能和 \(p_i^{a_i}\) 不互质,也就不存在逆元。
所以我们需要求出 \(m!\) 中 \(p_i\) 的指数以及把所有的 \(p_i\) 都除掉后的结果,这个可以递归去做。
对于没有 \(p_i\) 的那一部分,我们可以去计算逆元,对于含有 \(p_i\) 的那一部分,我们直接统计分子比分母多含有多少 \(p_i\),用快速幂去计算即可。
时间复杂度 \(plogp\)。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#define rg register
template<typename T>void read(rg T& x){
x=0;rg int fh=1;
rg char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
x*=fh;
}
const int maxn=1e5+5;
inline int addmod(rg int now1,rg int now2,rg int mod){
return now1+=now2,now1>=mod?now1-mod:now1;
}
inline int delmod(rg int now1,rg int now2,rg int mod){
return now1-=now2,now1<0?now1+mod:now1;
}
inline int mulmod(rg long long now1,rg int now2,rg int mod){
return now1*=now2,now1>=mod?now1%mod:now1;
}
int ksm(rg int ds,rg int zs,rg int mod){
rg int nans=1;
while(zs){
if(zs&1) nans=mulmod(nans,ds,mod);
ds=mulmod(ds,ds,mod);
zs>>=1;
}
return nans;
}
int getg(rg int nn,rg int p){
if(nn<p) return 0;
return getg(nn/p,p)+nn/p;
}
int getf(rg int nn,rg int p,rg int pk){
if(nn==0) return 1;
rg int nans=1,mans=1;
for(rg int i=1;i<=pk;i++){
if(i%p) mans=mulmod(mans,i,pk);
}
nans=ksm(mans,nn/pk,pk);
for(rg int i=nn/pk*pk+1;i<=nn;i++){
if(i%p) nans=mulmod(nans,i,pk);
}
return mulmod(nans,getf(nn/p,p,pk),pk);
}
int exgcd(rg int aa,rg int bb,rg int& xx,rg int& yy){
if(bb==0){
xx=1,yy=0;
return aa;
}
rg int nans=exgcd(bb,aa%bb,xx,yy);
rg int t=xx;
xx=yy;
yy=t-aa/bb*yy;
return nans;
}
int getinv(rg int val,rg int mod){
rg int xx=0,yy=0;
exgcd(val,mod,xx,yy);
xx=(xx%mod+mod)%mod;
return xx;
}
int getC(rg int nn,rg int mm,rg int p,rg int pk){
rg int cnt=getg(nn,p)-getg(nn-mm,p)-getg(mm,p);
rg int tmp1=getf(nn-mm,p,pk),tmp2=getf(mm,p,pk),tmp3=getf(nn,p,pk);
rg int nans=ksm(p,cnt,pk);
nans=mulmod(nans,tmp3,pk);
nans=mulmod(nans,getinv(tmp1,pk),pk);
nans=mulmod(nans,getinv(tmp2,pk),pk);
return nans;
}
int pri[maxn],pricnt,mi[maxn];
void divid(rg int mod){
for(rg int i=2;i*i<=mod;i++){
if(mod%i==0){
pri[++pricnt]=i;
mi[pricnt]=1;
while(mod%i==0){
mod/=i;
mi[pricnt]*=i;
}
}
}
if(mod>1){
pri[++pricnt]=mod;
mi[pricnt]=mod;
}
}
int a[maxn],M[maxn],t[maxn];
int crt(rg int nn,rg int mm,rg int mod){
for(rg int i=1;i<=pricnt;i++){
a[i]=getC(nn,mm,pri[i],mi[i]);
M[i]=mod/mi[i];
t[i]=getinv(M[i],mi[i]);
}
rg int ans=0;
for(rg int i=1;i<=pricnt;i++){
ans=addmod(ans,mulmod(a[i],mulmod(M[i],t[i],mod),mod),mod);
}
return ans;
}
int w[maxn],sum,ans=1;
int main(){
int n,m,mod;
read(mod),read(n),read(m);
divid(mod);
for(rg int i=1;i<=m;i++){
read(w[i]);
}
for(rg int i=1;i<=m;i++){
if(n<w[i]){
printf("Impossible\n");
return 0;
}
ans=mulmod(ans,crt(n,w[i],mod),mod);
n-=w[i];
}
printf("%d\n",ans);
return 0;
}