函数
- long long exlucas(long long n,long long m,long long P):求 Cnmmodp,p 不一定是质数。
代码
ll qmi(ll a,ll b,ll p){
ll ans=1%p;
while(b){
if(b&1)
ans=ans*a%p;
a=a*a%p;
b>>=1;
}
return ans;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
if(!b){
x=1;y=0;
return a;
}
ll d=exgcd(b,a%b,x,y);
ll tmp=x;
x=y;
y=tmp-a/b*x;
return d;
}
ll inv(ll a,ll p_k){
ll x,y;
exgcd(a,p_k,x,y);
return (x%p_k+p_k)%p_k;
}
ll fac(ll n,ll p,ll p_k){
if(!n)
return 1;
ll ans=1;
for(ll i=1;i<=p_k;i++)
if(i%p)
ans=ans*i%p_k;
ans=qmi(ans,n/p_k,p_k);
for(ll i=1;i<=n%p_k;i++)
if(i%p)
ans=ans*i%p_k;
return ans*fac(n/p,p,p_k)%p_k;
}
ll qC(ll n,ll m,ll p,ll p_k){
ll x=0,y=0,z=0;
for(ll i=p;i<=n;i*=p)
x+=n/i;
for(ll i=p;i<=m;i*=p)
y+=m/i;
for(ll i=p;i<=(n-m);i*=p)
z+=(n-m)/i;
return fac(n,p,p_k)*inv(fac(m,p,p_k),p_k)%p_k
*inv(fac(n-m,p,p_k),p_k)%p_k*qmi(p,x-y-z,p_k)%p_k;
}
long long CRT(int n,long long *a,long long *m){
long long sum=0,M=1,x,y;
for(int i=1;i<=n;i++)
M*=m[i];
for(int i=1;i<=n;i++){
sum+=a[i]*M/m[i]%M*(inv(M/m[i],m[i]))%M;
}
return (sum%M+M)%M;
}
ll exlucas(ll n,ll m,ll P){
ll tot=0;
for(ll p=2;p*p<=P;p++){
if(P%p)
continue;
ll p_k=1;
while(P%p==0){
p_k*=p;
P/=p;
}
a[++tot]=qC(n,m,p,p_k);
b[tot]=p_k;
}
if(P>1){
a[++tot]=qC(n,m,P,P);
b[tot]=P;
}
return CRT(tot,a,b);
}