[模板]卢卡斯定理/扩展卢卡斯定理

卢卡斯定理

用于求 n,m,p<1e5 p为素数 的C(n,m)%p

Lucas(n,m,p)=C(n%p,m%p)×Lucas(n​/p,m/p,p)

公式中的组合数部分预处理出阶乘然后求逆元算,后半部分递归解决,递归边界为m=0。

#include<bits/stdc++.h>
#define N 100010
using namespace std;
typedef long long ll;
ll a[N];
int p;
ll pow(ll y,int z,int p){
    y%=p;ll ans=1;
    for(int i=z;i;i>>=1,y=y*y%p)if(i&1)ans=ans*y%p;
    return ans;
}
ll C(ll n,ll m){
    if(m>n)return 0;
    return ((a[n]*pow(a[m],p-2,p))%p*pow(a[n-m],p-2,p)%p);
}
ll Lucas(ll n,ll m){
    if(!m)return 1;
    return C(n%p,m%p)*Lucas(n/p,m/p)%p;
}

int main(){
    int T=read();
    while(T--){
        cin>>n>>m>>p;
        a[0]=1;
        for(int i=1;i<=p;i++)a[i]=(a[i-1]*i)%p;
        cout<<Lucas(n+m,n)<<endl;
    }
}
洛谷p3807

扩展卢卡斯定理

用于求n,m,p<1e18 p的唯一分解中的每一项都小于1e6 的C(n,m)%p

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,m,mod;
inline ll pow(ll base,ll x,ll p){
    ll ans=1;
    while(x){
        if(x&1) ans=ans*base%p;
        base=base*base%p;
        x>>=1;
    }
    return ans;
}
inline ll exgcd(ll a,ll b,ll &x,ll &y){
    if(!b){
        x=1;y=0;
        return a;
    }
    ll r=exgcd(b,a%b,x,y);
    ll t=x;
    x=y;
    y=t-a/b*y;
    return r;
}
inline ll inv(ll a,ll b){
    ll x,y;
    return exgcd(a,b,x,y)==1?(x+b)%b:-1;
}
inline ll CRT(ll x,ll p){return x*inv(mod/p,p)%mod*mod/p%mod;}
inline ll fac(ll x,ll p,ll pp){
    if(!x) return 1;
    ll res=1;
    for(int i=2;i<=p;i++) if(i%pp) res=res*i%p;
    res=pow(res,x/p,p);
    for(int i=2;i<=x%p;i++) if(i%pp) res=res*i%p;
    return res*fac(x/pp,p,pp)%p;
}
inline ll C(ll n,ll m,ll p,ll pp){
    ll fn=fac(n,p,pp),fm=fac(m,p,pp),fnm=fac(n-m,p,pp);
    ll k=0;
    for(ll i=n;i;i/=pp) k+=i/pp;
    for(ll i=m;i;i/=pp) k-=i/pp;
    for(ll i=n-m;i;i/=pp) k-=i/pp;
    return fn*inv(fm,p)%p*inv(fnm,p)%p*pow(pp,k,p)%p;
}
inline ll exlucas(ll n,ll m){
    ll t=mod,ans=0;
    for(int i=2;i*i<=mod;i++)
        if(t%i==0){
            ll p=1;
            while(t%i==0) p*=i,t/=i;
            ans=(ans+CRT(C(n,m,p,i),p))%mod;
        }
    if(t>1) ans=(ans+CRT(C(n,m,t,t),t)%mod);
    return ans%mod;
}
int main(){
    cin>>n>>m>>mod;
    cout<<exlucas(n,m);
}
洛谷p4720
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll mod;
inline ll pow(ll base,ll x,ll p){
    ll ans=1;
    while(x){
        if(x&1) ans=ans*base%p;
        base=base*base%p;
        x>>=1;
    }
    return ans;
}
inline ll exgcd(ll a,ll b,ll &x,ll &y){
    if(!b){
        x=1;y=0;
        return a;
    }
    ll r=exgcd(b,a%b,x,y);
    ll t=x;
    x=y;
    y=t-a/b*y;
    return r;
}
inline ll inv(ll a,ll b){
    ll x,y;
    return exgcd(a,b,x,y)==1?(x+b)%b:-1;
}
inline ll CRT(ll x,ll p){return x*inv(mod/p,p)%mod*mod/p%mod;}
inline ll fac(ll x,ll p,ll pp){
    if(!x) return 1;
    ll res=1;
    for(int i=2;i<=p;i++) if(i%pp) res=res*i%p;
    res=pow(res,x/p,p);
    for(int i=2;i<=x%p;i++) if(i%pp) res=res*i%p;
    return res*fac(x/pp,p,pp)%p;
}
inline ll C(ll n,ll m,ll p,ll pp){
    ll fn=fac(n,p,pp),fm=fac(m,p,pp),fnm=fac(n-m,p,pp);
    ll k=0;
    for(ll i=n;i;i/=pp) k+=i/pp;
    for(ll i=m;i;i/=pp) k-=i/pp;
    for(ll i=n-m;i;i/=pp) k-=i/pp;
    return fn*inv(fm,p)%p*inv(fnm,p)%p*pow(pp,k,p)%p;
}
inline ll exlucas(ll n,ll m){
    ll t=mod,ans=0;
    for(int i=2;i*i<=mod;i++)
        if(t%i==0){
            ll p=1;
            while(t%i==0) p*=i,t/=i;
            ans=(ans+CRT(C(n,m,p,i),p))%mod;
        }
    if(t>1) ans=(ans+CRT(C(n,m,t,t),t)%mod);
    return ans%mod;
}
int main(){
    int a,b;
    cin>>mod>>a>>b;
    ll sum=0;
    int c[7];
    for(int i=1;i<=b;i++){
        cin>>c[i];
        sum+=c[i];
    }
    if(sum>a){
        cout<<"Impossible"<<'
';
        return 0;
    }
    ll ans=1;
    for(int i=1;i<=b;i++){
        ans=ans*exlucas(a,c[i]);
        ans%=mod;
        a-=c[i];
    }
    cout<<ans;
}
洛谷p2183
原文地址:https://www.cnblogs.com/xutianshu/p/10839753.html