【题意】就是求C(n,m)%p的值,p = p1*p2*…*pn;n,m <= 10^18,pi <= 10^5
【分析】网络赛就卡在这题上没拿到名额(虽然本来不报很大希望,毕竟单挑+专科渣);
首先阶乘是没有什么优化的,显然需要有个公式求C(n,m)%p;其实就是lucas定理,但是p过大也不能直接求,配合中国剩余定理就解决了(本弱太渣,没怎么看数论,不然应该秒出),注意下爆long long就可以。
【AC CODE】31ms
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f;
LL mul_mod(LL a, LL b, LL MOD)
{
a %= MOD;
LL ans = 0;
while(b)
{
if(b&1)
{
ans += a;
if(ans >= MOD) ans -= MOD;
}
a <<= 1;
if(a >= MOD) a -= MOD;
b >>= 1;
}
return ans;
}
LL pow_mod(LL x,LL n, LL MOD)
{
LL ans = 1;
while(n)
{
if(n&1) ans = mul_mod(ans,x,MOD);
x = mul_mod(x,x,MOD);
n >>= 1;
}
return ans;
}
LL getc(LL n,LL m, LL MOD)
{
if(n<m)return 0;
if(m>n-m)m=n-m;
LL s1=1,s2=1;
rep(i,0,m)
{
s1=s1*(n-i)%MOD;
s2=s2*(i+1)%MOD;
}
return s1*pow_mod(s2,MOD-2,MOD)%MOD;
}
LL lucas(LL n,LL m, LL MOD)
{
if(m==0)return 1;
return getc(n%MOD,m%MOD,MOD)*lucas(n/MOD,m/MOD,MOD)%MOD;
}
void e_gcd(LL a, LL b, LL& d, LL& x, LL& y)
{
if (!b) d = a, x = 1, y = 0;
else e_gcd(b, a%b, d, y, x), y -= x*(a / b);
}
LL crt(LL cnt, LL *m, LL *a)
{
LL aa = a[0];
LL mm = m[0];
rep(i,0,cnt)
{
LL sub = (a[i] - aa);
LL d, x, y;
e_gcd(mm, m[i], d, x, y);
if(sub % d) return -1;
LL new_m = m[i] / d;
new_m = (sub / d * x % new_m + new_m) % new_m;
aa = mm * new_m + aa;
mm = mm * m[i] / d;
}
aa = (aa + mm) % mm;
return aa;
}
LL a[20],d[20],p[20];
int main()
{
#ifdef SHY
freopen("d:\\1.txt", "r", stdin);
#endif
int t;
scanf("%d", &t);
while(t--)
{
LL n,m;
int k;
scanf("%I64d %I64d %d", &n, &m, &k);
rep(i,0,k)
{
scanf("%I64d", &p[i]);
a[i] = lucas(n,m,p[i]);
}
printf("%I64d\n", crt(k,p,a));
}
return 0;
}