题目链接:Unknown Treasure

这道题求得实际上是C(n,m)%M,M=p1·p2·p3···pk。又因为pi都是素数,故可用卢卡斯定理。但这里不可以直接用Lucas,因为Lucas的使用条件是“C(n,m)很大,但p不太大,同时p为素数”,而这里的M可能会很大。故我们可以先求C(n,m)%p1,C(n,m)%p2,C(n,m)%pk,然后再利用中国剩余定理得到最终答案。

代码如下:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
typedef long long LL;
//从n个苹果中挑出m个相互不同的苹果
LL mulq(LL a,LL b,LL m)        //(a*b)%m
{    
    LL ans=0;
    while(b)
    {
        if(b&1)
            ans=(ans+a)%m;
        a=(a+a)%m;
        b>>=1;
    }
    return ans;
}
LL powq(LL a,LL b,LL mod)
{
    LL ans=1;a%=mod;
    while(b)
    {
        if(b&1)
            ans=(ans*a)%mod;
        a=(a*a)%mod;
        b>>=1; 
    }
    return ans;
} 
LL inv(LL x,LL p)
{
    return powq(x,p-2,p);
}
LL comb(LL n,LL m,LL p)
{
    if(n<m||m<0)
        return 0;
    LL up=1;
    LL down=1;
    for(LL i=n-m+1;i<=n;i++)
        up=(up*i)%p;
    for(LL i=1;i<=m;i++)
        down=(down*i)%p;
    return up*inv(down,p)%p;
}
LL lucas(LL a,LL b,LL p)
{
    return !b?1:lucas(a/p,b/p,p)*comb(a%p,b%p,p)%p;
}
LL china(int k,LL a[],LL m[])
{
    LL M=1;LL ans=0;
    for(int i=0;i<k;i++)
        M*=m[i];
    for(int i=0;i<k;i++)
    {
        LL tmp=M/m[i];        //tmp==>mi        
        ans=(ans+mulq(tmp*inv(tmp,m[i]),a[i],M))%M;        //ti==>ti*mi=1 (mod mi)
    }
    return (ans+M)%M;            //通解为kM+∑(i=0,k)(ai*ti*Mi) 
}
int main()
{
    LL t,k;
    LL n,m;
    int cnt;
    LL r[15],md[15];
    scanf("%d",&t);
    while(t--)
    {    
        cnt=0;
        memset(r,0,sizeof(r));
        memset(md,0,sizeof(md));
        scanf("%lld %lld %lld",&n,&m,&k);
        for(int i=0;i<k;i++)
        {
            LL tmp=1;
            scanf("%lld",&tmp);
            md[cnt]=tmp;
            r[cnt++]=lucas(n,m,tmp);
        }
        LL pro=1;
        for(int i=0;i<k;i++)    
            pro*=md[i];
        LL ans=china(k,r,md);        //为什么答案就是中国剩余定理求出的值?不应该再模上乘积吗? 
        printf("%lld\n",ans%pro);    //因为中国剩余定理在计算时已经算了这个模;中国剩余定理求出的是解集中的最小解,即c(m,m)%M;
                                    //当然,如果在main中再模一次M,也是可以AC的    
    }
    return 0;
}