lucas定理 lucas(n,m,p)=C(n%p,m%p,p)*lucas(n/p,m/p,p),p是质数
证明:
n=ak*p^k+a(k-1)*p^(k-1)+........a0*p^0
m=bk*p^k+b(k-1)*p^(k-1)+........b0*p^0
(1+x)^p=1+x^p (mod p) p是质数 ,可以得到 (1+x)^(p^k)=1+x^(p^k) (mod p)
(1+x)^n=(1+x)^(ak*p^k)*(1+x)^(ak-1*p^(k-1))*........(1+x)^a0
=(1+x^(p^k))^ak*(1+x^(p^(k-1)))^ak-1*.........(1+x)^a0
C(n,m)x^m=C(ak,bk)*C(ak-1,bk-1)*.....C(a0,b0);
中国剩余定理:
a=a1 (mod n1)
a=a2 (mod n2)
.......
a=ak (mod nk)
M=n1*n2*n3*....nk
Mi=M/ni
Mi^(-1)是Mi在模ni下的逆元
n1,n2,n3...nk 是质数,a的一个解为 a= a1*M1*M1^(-1)+a2*M2*M2^(-1)+...........+ak*Mk*Mk^(-1)
证明 ai*Mi*Mi^(-1)%ni=ai j!=i aj*Mj*Mj^(-1)%ni=0 所以a%ni=ai;
这一题解法:
C(n,m)=ans[1] (mode n1)
C(n,m)=ans[2] (mode n2)
.....
C(n,m)=ans[k] (mode nk)
先用lucas求出ans[1..k],再用中国剩余定理求出C(n,m)
#include<bits/stdc++.h>
using namespace std;
#define rd(x) scanf("%d",&x)
#define rdd(x,y) scanf("%d%d",&x,&y)
#define rddd(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define rds(s) scanf("%s",s)
#define rep(i,n) for(int i=0;i<n;i++)
#define LL long long
const int N = 1e3+10;
const int inf=1e9;
const int MOD=1e9+7;
LL n,m;
int p[15];
int k;
void add(LL &a,LL b,LL md){
a+=b;
a%=md;
}
LL mul(LL a,LL b,LL md){
LL ret=0;
while(b){
if(b&1) add(ret,a,md);
add(a,a,md);
b>>=1;
}
return ret;
}
LL qmod(LL a,LL b,LL md){
LL ret=1;
while(b){
if(b&1) ret=mul(ret,a,md);
a=mul(a,a,md);
b>>=1;
}
return ret;
}
LL C(LL n,LL m,LL md){
LL up=1,down=1;
rep(i,m){
down=down*(i+1)%md;
up=up*(n-i)%md;
}
return mul(up,qmod(down,md-2,md),md);
}
LL lucas(LL n,LL m,LL md){
if(n==0 || m==0) return 1;
return mul(C(n%md,m%md,md),lucas(n/md,m/md,md),md);
}
LL M;
LL ans[15];
int main()
{
#ifndef ONLINE_JUDGE
freopen("aaa","r",stdin);
#endif
int T;
rd(T);
while(T--){
scanf("%I64d%I64d%d",&n,&m,&k);
M=1;
rep(i,k) scanf("%d",p+i+1);
for(int i=1;i<=k;i++){
ans[i]=lucas(n,m,p[i]);
M*=p[i];
}
LL ret=0;
for(int i=1;i<=k;i++){
LL Mi=M/p[i];
LL Mni=qmod(Mi,p[i]-2,p[i]);
ret+=mul(mul(ans[i],Mi,M),Mni,M);
ret%=M;
}
printf("%I64d\n",ret);
}
return 0;
}