模板更新 扩展卢卡斯

写个模板。扩展卢卡斯。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
ll fac[N],PI[N],PK[N],cnt;
ll qmod(ll a,ll b,ll p)
{
    ll ans=1;
    while(b)
    {
        if(b&1)ans=ans*a%p;
        a=a*a%p;b>>=1;
    }
    return ans;
}
void exgcd(ll a,ll b,ll &x,ll &y)
{
    if(!b){x=1;y=0;return;}
    exgcd(b,a%b,y,x);y-=a/b*x;
}
ll inv(ll n,ll p)
{
    ll a=n,b=p,x,y;
    exgcd(a,b,x,y);
    x=(x%b+b)%b; 
    if(!x)x+=b;
    return x;
}
ll mul(ll n,ll pi,ll pk)
{
    if(!n)return 1;
    ll ans=1;
    if(n/pk)
    {
        ans=ans*fac[pk]%pk;
        ans=qmod(ans,n/pk,pk)%pk;
    }
    ans=ans*fac[n%pk]%pk;
    return ans*mul(n/pi,pi,pk)%pk;
}
ll C(ll n,ll m,ll p,ll pi,ll pk)
{
    if(n<m)return 0;int k=0;ll ans=1;
    fac[0]=fac[1]=1;
    for(int i=2;i<=pk;++i)
    {
        if(i%pi)fac[i]=fac[i-1]*i%pk;
        else fac[i]=fac[i-1];
    }
    ll a=mul(n,pi,pk),b=mul(m,pi,pk),c=mul(n-m,pi,pk);
    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;
    ans=a*inv(b,pk)%pk*inv(c,pk)%pk*qmod(pi,k,pk)%pk;
    return ans*(p/pk)%p*inv(p/pk,pk)%p;
}
ll CRT(ll n,int m,int p)
{
    if(n<m)return 0;ll ans=0;
    for(int i=1;i<=cnt;++i)
    {
        ans=(ans+C(n,m,p,PI[i],PK[i]))%p;
    }
    return ans;
}
void pri(int p)
{
    cnt=0;
    for(int i=2;i*i<=p;++i)
    {
        if(p%i==0)
        {
            PI[++cnt]=i;PK[cnt]=1;
            while(p%i==0)p/=i,PK[cnt]*=i;
        }
    }
    if(p!=1)PI[++cnt]=PK[cnt]=p;
    return;
}
int main()
{
    int T;scanf("%d",&T);ll n,m,p;
    while(T--)
    {
        scanf("%lld%lld%lld",&n,&m,&p);pri(p);//n+=m;
        printf("%lld\n",CRT(n,m,p));
    }
    return 0;
}

 

posted @ 2018-03-19 15:11  大奕哥&VANE  阅读(172)  评论(0编辑  收藏  举报