【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));
}
 
posted @ 2018-10-19 10:04  Newuser233  阅读(6)  评论(0)    收藏  举报