On the way to the next secret treasure hiding place, the mathematician discovered a cave unknown to the map. The mathematician entered the cave because it is there. Somewhere deep in the cave, she found a treasure chest with a combination lock and some numbers on it. After quite a research, the mathematician found out that the correct combination to the lock would be obtained by calculating how many ways are there to pick m different apples among n of them and modulo it with M. M is the product of several different primes.
Input
On the first line there is an integer T(T≤20) representing the number of test cases.
Each test case starts with three integers n,m,k (1≤m≤n≤1018, 1≤k≤10) on a line where k is the number of primes. Following on the next line are k different primes p1,…,pk. It is guaranteed that M=p1⋅p2⋯pk≤1018 and pi≤105 for every i∈{1,…,k}.
Output
For each test case output the correct combination on a line.
Samples
Input
1
9 5 2
3 5
Output
6
题意求C(n,m)%M (n,m)<=1e18,M可以分解为若干个素数p1,p2,…的乘积
拓展卢卡斯定理
首先对p进行质因数分解:
p=∏pi^ki;
所以如果分别求出C(n,m) mod piki,就可以构造出若干个形如C(n,m)=ai mod piki的方程,然后用中国剩余定理即可求解。
题目中已经给出p1,p2,p3…均为素数,所以构造a[i]=C(n,m)%p[i]=X(%p[i])的一系列方程,用中国剩余定理求出X就是最终结果,由于数据较大,需要使用按位乘法防止数据爆longlong.
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+7;
ll fac[maxn];
ll inv[maxn];
ll fast_cheng(ll a,ll b,ll mod)
{
if(b<0)b=(b%mod+mod)%mod;
a%=mod;
if(a<b)swap(a,b);
ll ans = 0;
while(b){
if(b & 1) ans = (ans+a)%mod;
b>>=1;
a = (a+a)%mod;
}
return ans;
}
ll fast_pow(ll a, ll b, ll mod)
{
ll ans = 1;
while(b){
if(b & 1) ans = (ans*a)%mod;
b>>=1;
a = (a*a)%mod;
}
return ans;
}
ll exgcd(ll a, ll b, ll &x, ll &y)
{
if (b == 0)
{
x = 1, y = 0;
return a;
}
ll ret = exgcd(b, a%b, y, x);
y -= a / b * x;
return ret;
}
void init(ll n,ll m,ll mod)
{
fac[0]=fac[1]=1;
for (ll i=2;i<=n;i++)
fac[i]=fac[i-1]*i%mod;
inv[m]=fast_pow(fac[m],mod-2,mod);
inv[n-m]=fast_pow(fac[n-m],mod-2,mod);
}
ll com(ll n,ll m,ll mod)
{
if (m>n) return 0;
if (m==n) return 1;
init(n,m,mod);
return fac[n]*inv[n-m]%mod*inv[m]%mod;
}
ll C(ll n,ll m,ll mod)
{
if (m==0)
return 1;
return fast_cheng(C(n/mod,m/mod,mod),com(n%mod,m%mod,mod),mod);
}
ll p[50];
ll a[50];
ll China(ll a[],ll m[],int hh)
{
ll M=1,Mi,ans=0;
ll x,y,d;
for(int i=1;i<=hh;i++)
M*=m[i];
for(int i=1;i<=hh;i++)
{
Mi=M/m[i];
d=exgcd(Mi,m[i],x,y);
ans=(ans+fast_cheng(fast_cheng(Mi,x,M),a[i],M))%M;
}
if(ans<0) ans+=M;
return ans;
}
ll n,m,k;
int main()
{
int T;
cin>>T;
int k;
//cout<<C(3,2,10) ;
while(T--)
{
scanf("%lld %lld %d",&n,&m,&k);
for(int i=1;i<=k;i++)
scanf("%lld",&p[i]);
for(int i=1;i<=k;i++)
a[i]=C(n,m,p[i]);
//cout<<a[i]<<endl;
cout<<China(a,p,k)<<endl;
}
}