比较套路的题,对于每个$p$,用$lucas$定理爆算,然后拿$CRT$合并即可。
#include <bits/stdc++.h> using namespace std; #define LL long long #define rep(i,x,y) for(int i=(x);i<=(y);++i) int pri[12]; int fac[100010][12], inv[100010][12]; LL n,m;int k; inline void init() { rep(i,1,k){ fac[0][i]=1; rep(j,1,pri[i]-1){ fac[j][i]=1ll*fac[j-1][i]*j%pri[i]; } inv[0][i]=inv[1][i]=1; rep(j,2,pri[i]-1){ inv[j][i]=1ll*inv[pri[i]%j][i]*(pri[i]-pri[i]/j)%pri[i]; } rep(j,1,pri[i]-1){ inv[j][i]=1ll*inv[j-1][i]*inv[j][i]%pri[i]; } } } inline int Power(int x,int y,int MOD){ int ret=1; while(y){ if(y&1)ret=1ll*ret*x%MOD; x=1ll*x*x%MOD;y>>=1; } return ret; } inline int C(int x,int y,int p){ if(x<y)return 0; return 1ll*fac[x][p]*inv[x-y][p]%pri[p]*inv[y][p]%pri[p]; } inline LL lucas(LL x,LL y,LL p){ if(x<pri[p]&&y<pri[p])return C(x,y,p); return lucas(x/pri[p],y/pri[p],p)*lucas(x%pri[p],y%pri[p],p)%pri[p]; } inline LL mul(LL x,LL y,LL P){ LL ret=0; while(x){ if(x&1){ ret+=y; if(ret>=P)ret-=P; } y+=y; if(y>=P)y-=P; x>>=1; } return ret; } inline void solve(){ scanf("%lld%lld%d",&n,&m,&k); LL P=1; rep(i,1,k){ scanf("%d",&pri[i]); P*=pri[i]; } init(); LL res=0; rep(i,1,k){ LL Mi=P/pri[i],inv_Mi=Power(Mi%pri[i],pri[i]-2,pri[i]); LL tmp=lucas(n,m,i); tmp=mul(tmp,Mi*inv_Mi,P); res+=tmp; if(res>=P)res-=P; } printf("%lld ",res); } int main(){ int T; scanf("%d",&T); while(T--){ solve(); } }