扩展Lucas
Lucas用于模数是质数的情况,如果模数不是质数,就要用到扩展卢卡斯
思想
把模数质因子分解
对于每一个pi^ki做一遍普通Lucas,最后中国剩余定理合并。
要理解的是过程
其实就是算fac的时间更优了(充分利用阶乘的性质就不用O(n)预处理)
结合代码会更好理解~
#include<bits/stdc++.h> #define LLL long long using namespace std; LLL read() { LLL f=1,x=0;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} return x*f; } LLL quick(LLL a,LLL x,LLL p) { LLL ans=1; while(x) { if(x&1) ans=ans*a%p; a=a*a%p;x>>=1; } return ans%p; } /*LL inv(LL x,LL p) { return quick(x,p-2,p); }*/ void exgcd(LLL a,LLL b,LLL &x,LLL &y) { if(!b){x=1,y=0;return;} exgcd(b,a%b,x,y); LLL t=x; x=y;y=t-(a/b)*y; } LLL inv(LLL a,LLL b) { LLL x,y; exgcd(a,b,x,y); return (x%b+b)%b; } LLL fac(LLL n,LLL x,LLL p) { if(!n) return 1; LLL ans=1; for(LLL i=1;i<=p;++i) if(i%x)ans=ans*i%p;//不含因子x ans=quick(ans,n/p,p);//有循环节,所以乘积用快速幂计算即可(整块的) for(LLL i=1;i<=n%p;i++)//未构成整块的 if(i%x) ans=ans*i%p; return ans*fac(n/x,x,p)%p;//当前的不含因子x的乘积乘以递归下去求的剩余阶乘部分的结果 } LLL cal(LLL n,LLL m,LLL x,LLL p)//x是当前质数,p是题目要求质数 { LLL N=fac(n,x,p),M=fac(m,x,p),Z=fac(n-m,x,p); //计算出对于每一个质数的若干次方取模后的结果 LLL cnt=0; for(LLL i=n;i;i/=x) cnt+=i/x; for(LLL i=m;i;i/=x) cnt-=i/x; for(LLL i=n-m;i;i/=x) cnt-=i/x; LLL ans=quick(x,cnt,p)*N%p*inv(M,p)%p*inv(Z,p)%p; return ans%p; } LLL CRT(LLL a,LLL p,LLL x) { return inv(p/x,x)*(p/x)%p*a%p; } void exlucas(LLL n,LLL m,LLL p) { LLL t=p,ans=0; for(LLL i=2;i*i<=p;++i) { LLL k=1; if(t%i)continue; while(t%i==0){k=k*i;t=t/i;} ans=(ans+CRT(cal(n,m,i,k),p,k))%p; } if(t>1)ans=(ans+CRT(cal(n,m,t,t),p,t))%p; printf("%lld\n",ans%p); } int main() { LLL n=read(),m=read(),p=read(); exlucas(n,m,p); }