求 C(n,m) %p的结果。当n太大时,我们无法打阶乘表,所以我们采用Lucas定理来求组合数。
一 n , m ,mod 较大,mod为素数
#include <iostream>
#include <cstdio>
#define LL long long
using namespace std;
LL quick( LL a, LL b, LL p )
{
LL ans = 1LL;
while( b )
{
if( b & 1 ) ans = ( ans * a ) % p ;
a = ( a * a ) % p ;
b >>= 1 ;
}
return ans ;
}
LL fac( LL x, LL p )
{
LL ans = 1;
for( int i = 2 ; i <= x ; i ++ ) ans = ( ans * i ) % p;
return ans;
}
LL C( LL n, LL m, LL p )
{
if( m < 0 || n < m ) return 0;
if( m == 0 ) return 1 ;
m = min( m, n - m );
LL a = 1LL, b = 1LL;
for( LL i = 1 ; i <= m ; i++ )
{
a = a * (n - i + 1) % p ;
b = ( b * i ) % p;
}
return a * quick( b, p - 2, p ) % p ;
}
LL Lucas( LL n, LL m, LL p )
{
return m ? C( n % p, m % p, p ) * Lucas( n / p, m / p, p ) % p : 1 ;
}
int main()
{
int T;
LL n, m, p;
scanf("%d",&T);
while( T-- )
{
scanf("%lld%lld%lld",&n,&m,&p);
LL res = Lucas( n, m, p );
printf("%lld\n",res);
}
return 0 ;
}
扩展卢卡斯(p不一定为素数)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll quick_mod(ll a,ll b,ll m) //快速幂
{
ll ans=1ll;
while(b)
{
if(b&1) ans=ans*a%m;
b>>=1;
a=a*a%m;
}
return ans;
}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(a%b==0)
{
x=0ll;
y=1ll;
return b;
}
ll v,tx,ty;
v=exgcd(b,a%b,tx,ty);
x=ty;
y=tx-a/b*ty;
return v;
}
ll inv(ll a,ll p)
{
if(!a) return 0ll;
ll x,y;
exgcd(a,p,x,y);
x=(x%p+p)%p;
return x;
}
ll Mul(ll n,ll pi,ll pk)
{
if(!n) return 1ll;
ll ans=1ll;
for(ll i=2; i<=pk; i++)
if(i%pi) ans=ans*i%pk;
ans=quick_mod(ans,n/pk,pk);
for(ll i=2; i<=n%pk; i++)
{
if(i%pi) ans=ans*i%pk;
}
return ans*Mul(n/pi,pi,pk)%pk;
}
ll exlucas(ll n,ll m,ll p,ll pi,ll pk)
{
if(m>n) return 0ll;
ll a=Mul(n,pi,pk);
ll b=Mul(m,pi,pk);
ll c=Mul(n-m,pi,pk);
ll k=0ll,ans=0ll;
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*quick_mod(pi,k,pk)%pk;
return ans*(p/pk)%p*inv(p/pk,pk)%p; //中国剩余定理 a[i]*M*x 余数*其他个个素数的乘积*x
}
int main()
{
ll n,m,p,ans=0;
while(cin>>n>>m>>p)
{
for(ll x=p,i=2; i<=p; i++)
{
if(x%i==0)
{
ll pk=1ll;
while(x%i==0) pk*=i,x/=i;
ans=(ans+exlucas(n,m,p,i,pk))%p;
}
}
cout<<ans<<endl;
ans=0;
}
return 0;
}