题意:求C(n,m)%p p = p1 * p2 *....*pk;
Lucas定理 + 中国剩余定理
http://blog.sina.com.cn/s/blog_12fea76590102w6ts.html
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> #include <cmath> #include <set> #include <queue> using namespace std; #define ll long long const int N = 20; ll A[N], B[N]; ll q_pow(ll x,ll y, ll p){ ll ret = 1; while(y){ if(y&1)ret = (ret*x)%p; x = (x*x)%p; y >>= 1; } return ret; } ll Cm(ll n, ll m, ll p){ if(n < m)return 0; if(n == m)return 1; if(m > n-m)m = n-m; ll ans = 1, cn = 1, cm = 1; while(m){ cn = (cn * n)%p; cm = (cm * m)%p; n--,m--; } ans = (cn * q_pow(cm,p-2,p))%p; return ans; } ll Lucas(ll n, ll m, ll p){ if(m == 0)return 1; return Cm(n%p,m%p,p) * Lucas(n/p, m/p, p)%p; } ll Ex_gcd(ll a, ll b,ll &x, ll &y){ if(b == 0){ x = 1; y = 0; return a; } ll ret = Ex_gcd(b, a%b, y, x); y -= a/b*x; return ret; } ll multi(ll a,ll b,ll p){ ll ret = 0; while(b){ if(b&1)ret = (ret + a)%p; a = (a+a)%p; b>>=1; } return ret; } ll china(ll n, ll *m, ll *a){ ll M = 1, d, y, x = 0; for(int i = 0; i < n; i++){ M *= m[i]; } for(int i = 0; i < n; i++){ ll w = M / m[i]; d = Ex_gcd(m[i], w, d, y); //multi(y,w,M) = w*w^-1 (w^-1)为w/m[i]%M的逆元 x = (x + multi(multi(y, w, M), a[i], M))%M; } return (x+M)%M; } int main(){ int T, k; ll n, m; scanf("%d",&T); while(T--){ scanf("%lld%lld%d",&n,&m,&k); for(int i = 0; i < k; i++){ scanf("%lld",A+i); B[i] = Lucas(n, m, A[i]); } printf("%lld\n",china(k,A,B)); } return 0; }