http://www.cnblogs.com/jianglangcaijin/p/3446839.html
Lucas定理用来求解大组合数取余 C(n,m)%mod,具体证明啊,我就不证了,只是来当黑盒,==,原谅我的弱。。
第一类 C(n,m)%mod,mod 是个质数,这样的话,直接套模板,HDU3037。。
ll getFactor(ll p)//求因子
{
fac[0] = 1;
for(int i = 1;i<=p;i++)
{
fac[i] = (fac[i - 1]*i)%p;
}
}
ll Lucas(ll n,ll m,ll p)//大组合数取余
{
ll ret = 1;
while(n&&m)
{
ll a = n%p, b = m%p;
if(a<b) return 0;
ret = (ret*fac[a]*modpow(fac[b]*fac[a - b]%p , p - 2, p)) %p;
n/=p;
m/=p;
}
return ret;
}
第二类 C(n,m)%mod,mod 是合数,这样的话,把mod变成质数的乘积,然后对每个质数求lucas,最后用中国剩余定理,求解一元用余方程,HDU5446。。
ll fac[MAX];//因子
ll p[109];
ll lucas[109];
ll n,m,k;
ll modpow(ll a,ll b,ll mod)//a^b%mod
{
ll ret = 1;
while(b)
{
if(b&1) ret = (ret*a)%mod;
a = (a*a)% mod;
b>>=1;
}
return ret;
}
ll modmul(ll a,ll b,ll mod)//a*b%mod;
{
ll ret = 0;
while(b)
{
if(b&1) ret = (ret + a)%mod;
a = (a + a)% mod;
b>>=1;
}
return ret;
}
ll getFactor(ll p)//求因子
{
fac[0] = 1;
for(int i = 1;i<=p;i++)
{
fac[i] = (fac[i - 1]*i)%p;
}
}
ll Lucas(ll n,ll m,ll p)//大组合数取余
{
ll ret = 1;
while(n&&m)
{
ll a = n%p, b = m%p;
if(a<b) return 0;
ret = (ret*fac[a]*modpow(fac[b]*fac[a - b]%p , p - 2, p)) %p;
n/=p;
m/=p;
}
return ret;
}
ll exgcd(ll a,ll b,ll &x,ll &y)//拓展欧几里得
{
if(!b)
{
x = 1 , y = 0;
return a;
}
int ans = exgcd(b , a%b, y , x);
y-=a/b*x;
return ans;
}
ll CRT(ll *a,ll *m,int len)//中国剩余定理
{
ll d,x,y,ret = 0;
ll M = 1;
for(int i = 0;i < len;i++) M*=m[i];
for(int i = 0;i < len;i++)
{
ll w = M/m[i];
d = exgcd(m[i],w,x,y);
ret = (ret + modmul(modmul(y, w, M), a[i], M) ) % M;
}
return (ret + M) % M;
}
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("an.txt","r", stdin);
#endif
int T;
scanf("%d",&T);
while(T--)
{
scanf("%lld%lld%d",&n,&m,&k);
for(int i = 0; i<k; i++)
{
scanf("%I64d",&p[i]);
getFactor(p[i]);
lucas[i] = Lucas(n,m,p[i]);
}
ll ans = CRT(lucas,p,k);
printf("%I64d\n",ans);
}
return 0;
}
第三类, C(n,m)%mod^t
ll POW(ll a,ll b,ll mod)
{
ll ans=1;
while(b)
{
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
ll POW(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1) ans=ans*a;
a=a*a;
b>>=1;
}
return ans;
}
ll exGcd(ll a,ll b,ll &x,ll &y)
{
ll t,d;
if(!b)
{
x=1;
y=0;
return a;
}
d=exGcd(b,a%b,x,y);
t=x;
x=y;
y=t-a/b*y;
return d;
}
bool modular(ll a[],ll m[],ll k)
{
ll d,t,c,x,y,i;
for(i=2;i<=k;i++)
{
d=exGcd(m[1],m[i],x,y);
c=a[i]-a[1];
if(c%d) return false;
t=m[i]/d;
x=(c/d*x%t+t)%t;
a[1]=m[1]*x+a[1];
m[1]=m[1]*m[i]/d;
}
return true;
}
ll reverse(ll a,ll b)
{
ll x,y;
exGcd(a,b,x,y);
return (x%b+b)%b;
}
ll C(ll n,ll m,ll mod)
{
if(m>n) return 0;
ll ans=1,i,a,b;
for(i=1;i<=m;i++)
{
a=(n+1-i)%mod;
b=reverse(i%mod,mod);
ans=ans*a%mod*b%mod;
}
return ans;
}
ll C1(ll n,ll m,ll mod)
{
if(m==0) return 1;
return C(n%mod,m%mod,mod)*C1(n/mod,m/mod,mod)%mod;
}
ll cal(ll n,ll p,ll t)
{
if(!n) return 1;
ll x=POW(p,t),i,y=n/x,temp=1;
for(i=1;i<=x;i++) if(i%p) temp=temp*i%x;
ll ans=POW(temp,y,x);
for(i=y*x+1;i<=n;i++) if(i%p) ans=ans*i%x;
return ans*cal(n/p,p,t)%x;
}
ll C2(ll n,ll m,ll p,ll t)
{
ll x=POW(p,t);
ll a,b,c,ap=0,bp=0,cp=0,temp;
for(temp=n;temp;temp/=p) ap+=temp/p;
for(temp=m;temp;temp/=p) bp+=temp/p;
for(temp=n-m;temp;temp/=p) cp+=temp/p;
ap=ap-bp-cp;
ll ans=POW(p,ap,x);
a=cal(n,p,t);
b=cal(m,p,t);
c=cal(n-m,p,t);
ans=ans*a%x*reverse(b,x)%x*reverse(c,x)%x;
return ans;
}
//计算C(n,m)%mod
ll Lucas(ll n,ll m,ll mod)
{
ll i,t,cnt=0;
ll A[205],M[205];
for(i=2;i*i<=mod;i++) if(mod%i==0)
{
t=0;
while(mod%i==0)
{
t++;
mod/=i;
}
M[++cnt]=POW(i,t);
if(t==1) A[cnt]=C1(n,m,i);
else A[cnt]=C2(n,m,i,t);
}
if(mod>1)
{
M[++cnt]=mod;
A[cnt]=C1(n,m,mod);
}
modular(A,M,cnt);
return A[1];
}