[模板]卢卡斯定理/扩展卢卡斯定理
卢卡斯定理
用于求 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。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; } }
扩展卢卡斯定理
用于求n,m,p<1e18 p的唯一分解中的每一项都小于1e6 的C(n,m)%p
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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); }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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"<<'\n'; 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; }