HDU 5446 Unknown Treasure ACM/ICPC 2015 Changchun Online(Lucass+CRT)

来源:互联网 发布:电脑运行apk软件 编辑:程序博客网 时间:2024/06/14 22:20

Unknown Treasure

Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 2901    Accepted Submission(s): 1059

Problem Description

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 pickm 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(T20) representing the number of test cases.
Each test case starts with three integers n,m,k(1mn1018,1k10) 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=p1p2pk1018 and pi105 for every i{1,...,k}.

Output

For each test case output the correct combination on a line.

Sample Input

19 5 23 5

Sample Output

6

Source

2015 ACM/ICPC Asia Regional Changchun Online



        可以说是一道裸题,求C(n,m)对p1*p2*……pn取模,这个n、m都可以到1e18级别,然后pi是1e5级别。

        如果说只对一个质数p取模,而且质数不大,那么我们直接可以用Lucass定理拆分求组合数,这个我之前讲过了,我就不多说了。关键是,本题取模是对很多质数的乘积取模,故不能直接用Lucass定理。如果我们设最后答案为X,那么X=C(n,m)%(p1p2……pn)。根据同余的性质,我们可以有X%pi=C(n,m)%pi,这个很容易理解,于是我们X对于所有的pi的方程都写出来。则有:

                                                                      

        发现了什么吗?这个就相当于是一系列的同余方程,然后我们要做的就是解这个同余方程。如此,我们就可以用中国剩余定理CRT了。下面,再大致的讲讲中国剩余定理吧:

                                              

        定理知道之后,我们就只需要对应的求出每一个质数pi对应的用Lucass定理计算之后的组合数的余数,然后把把余数和除数代入,用中国剩余定理(CRT)解方程即可。具体的话要注意中间乘的时候LL*LL,可能会爆,所以可以用按位乘来解决。当然了,HDU比较高级,可以直接用__int128,但是现场可能是没有的,所以我还是写了一遍按位乘。具体见代码:

#include<bits/stdc++.h>#define LL long long#define N 101000using namespace std;LL f[N],a[11],Mod[11],n,m,k;LL multiply(LL a,LL b,LL mod){    LL res=0;    while(b)    {        if(b&1) res=(res+a)%mod;        b>>=1;a=(a+a)%mod;    }    return res;}LL qpow(LL x,int n,int p){    LL ret=1;    while (n)    {        if (n&1) ret=ret*x%p;        x=x*x%p; n>>=1;    }    return ret;}LL ex_gcd(LL a,LL b,LL &x,LL &y){    if(b==0){x=1,y=0;return a;}    else    {        LL r=ex_gcd(b,a%b,y,x);        y-=x*(a/b); return r;    }}void init(int p){    f[0]=1;    for(int i=1;i<=p;i++)        f[i]=f[i-1]*i%p;}LL lucass(LL n,LL m,int p){    init(p);    LL ret=1;    while (n&&m)    {        int a=n%p,b=m%p;        if (a<b) return 0;        ret=ret*f[a]*qpow(f[b]*f[a-b]%p,p-2,p)%p;        n/=p,m/=p;    }    return ret;}LL CRT(LL a[],LL m[],int n){    LL M=1,res=0;    for(int i=1;i<=n;i++) M*=m[i];    for(int i=1;i<=n;i++)    {        LL x,y,Mi=M/m[i];        ex_gcd(m[i],Mi,x,y);//ex_gcd求逆元        res=(res+multiply(multiply(y,Mi,M),a[i],M))%M;    }    if(res<0) res+=M;    return res;}int main(){    int T_T;    cin>>T_T;    while(T_T--)    {        scanf("%I64d%I64d%I64d",&n,&m,&k);        for(int i=1;i<=k;i++)        {            scanf("%I64d",&a[i]);            Mod[i]=lucass(n,m,a[i]);        }        printf("%I64d\n",CRT(Mod,a,k));    }    return 0;}

X=Cmn%(pi)

阅读全文
0 0