题目描述:
题意无比简单,n,m,k求组合数C(n,m)%knum,其中knum由p1,p2,p3...pk,k个数相乘得到。这题麻烦的是超大的数据范围,所以我们要综合应用一些东西,由于knum是k个数的乘积,我们可以现将这k个数拆开计算,对于每一个C(n,m)%pi就是一个lucas,做完这些lucas之后我们可以得到一个线性同余方程,接下来就是中国剩余定理的过程了。相信做到这个题的时候,lucas和中国剩余定理应该都是会的,不会自信百度。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<stack>
#include<queue>
#include<algorithm>
using namespace std;
long long fact[100010];
long long qpow(long long x,long long y,long long MOD)
{
long long res=1;
while(y)
{
if (y&1)
res=(res*x)%MOD;
//printf("--%lld\n",res);
x=(x*x)%MOD;
//printf("---%lld\n",x);
y=y>>1;
}
return res;
}
long long mod_inverse(long long a,long long m)//求逆元。
{
long long inv=qpow(a,m-2,m);
//printf("%lld\n",inv);
return inv;
}
long long mod_fact(long long n,long long p,long long &e)//阶乘取模。
{
e=0;
if (n==0) return 1;
long long res=mod_fact(n/p,p,e);
e+=n/p;
if (n/p%2!=0) return res*(p-fact[n%p])%p;
return res*fact[n%p]%p;
}
long long mod_comb(long long n,long long k,long long p)//组合数取模,Lucas
{
if (n<0||k<0||n<k) return 0;
long long e1,e2,e3;
long long a1=mod_fact(n,p,e1);
long long a2=mod_fact(k,p,e2);
long long a3=mod_fact(n-k,p,e3);
if (e1>e2+e3) return 0;
return a1*mod_inverse(a2*a3%p,p)%p;
}
void fact_init(long long p)//阶乘打表
{
fact[0]=1;
for (int i=1;i<=p;i++)
fact[i]=(fact[i-1]*i)%p;
}
long long multi_mod(long long x,long long y,long long c)
{
x=(x%c+c)%c;
y=(y%c+c)%c;
long long ans=0;
while(y){
if(y&1)ans=ans+x;
if(ans>=c)ans-=c;
x=x+x;
if(x>=c)x-=c;
y>>=1;
}
return ans;
}
long long extgcd(long long a,long long b,long long &x,long long &y)//扩展欧几里德求逆元。
{
long long d=a;
if (b!=0)
{
d=extgcd(b,a%b,y,x);
y-=(a/b)*x;
}
else
{
x=1;
y=0;
}
return d;
}
long long CRT(long long n,long long a[],long long b[])
{
long long M=1,d,y,x=0;
for (int i=1;i<=n;i++) M=M*a[i];
for (int i=1;i<=n;i++)
{
long long w=M/a[i];
long long l=extgcd(a[i],w,d,y);
x=(x+multi_mod(multi_mod(y,w,M),b[i],M));
}
return (x+M)%M;
}
long long n,m,k;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%I64d%I64d%I64d",&n,&m,&k);
long long p;
long long a[22],b[22];
for (long long i=1;i<=k;i++)
{
scanf("%I64d",&p);
a[i]=p;
fact_init(p);
b[i]=mod_comb(n,m,p);
}
long long ans=CRT(k,a,b);
printf("%I64d\n",ans);
}
return 0;
}