【MOBAN】扩展卢卡斯模板
实在菜之至极
处理问题:求[latex][Cn,m)\% P] [/latex],其中P不一定为质数。方法-->讲P分解为[latex][\prod {{P_i}^{ki}} ][/latex],这样的话,我们就拆分成了若干个互质的质数,分别求出C(n,m)%[latex][{{P_i}^{ki}}][/latex],然后利用中国剩余定理合并一下就可以了,至于对于一个pi^ki求C(n,m),我们之需要将%pi==0单独提出来考虑,就可以搞了(据说时间复杂度最坏是PlogP?)。
具体代码说话:
#include<iostream> #include<cstdio> #include<cmath> using namespace std; typedef long long ll; ll p; ll ans; void exgcd(ll a,ll b,ll &x,ll &y) { if(b==0) { x = 1; y = 0; return; } exgcd(b,a%b,x,y); ll tx = x; x = y; y = tx - (a/b)*y; } ll inv(ll a,ll mod) { ll tmp,y; exgcd(a,mod,tmp,y); return tmp<0?tmp+mod:tmp; } ll ksm(ll a,ll b,ll mod) { ll res = 1; for(;b;b>>=1,a=a*a%mod) if(b&1) res = res*a%mod; return res; } void crt(ll res,ll mod) { ans = (ans + res*(p/mod)%p*inv(p/mod,mod)%p)%p; } ll fac(ll n,ll pi,ll pk) { if(!n) return 1; ll res = 1; for(ll i=2;i<=pi-1;i++) res*=i,res%=pk; res = ksm(res,n/pi,pk); for(ll i=2;i<=n%pi;i++) res*=i,res%=pk; return res*fac(n/pi,pi,pk)%pk; } ll C(ll n,ll m,ll pi,ll pk) { ll d1 = fac(n,pi,pk); ll d2 = fac(m,pi,pk); ll d3 = fac(n-m,pi,pk); ll k = 0; for(ll i=n;i;i/=pi) k+=i/pi; for(ll i=m;i;i/=pi) k-=i/pi; for(ll i=n-m;i;i/=pi) k-=i/pi; return d1*inv(d2,pk)%pk*inv(d3,pk)%pk*ksm(pi,k,pk)%pk; } ll lucas(ll n,ll m) { ll o = p; for(ll pi=2;pi*pi<=o;pi++) { if(o%pi==0) { ll pk = 1; while(o%pi==0) pk*=pi,o/=pi; crt(C(n,m,pi,pk),pk); } } if(o>1) crt(C(n,m,o,o),o); return ans; } int main() { ll n,m; scanf("%lld%lld%lld",&n,&m,&p); printf("%lld",lucas(n,m)); }