hdu5446 Unknown Treasure(数论综合题:大组合数取大合数模:Lucas+CRT)

来源:互联网 发布:ubuntu开发c语言 编辑:程序博客网 时间:2024/05/27 10:43


Link:http://acm.hdu.edu.cn/showproblem.php?pid=5446

Unknown Treasure

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


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 pick m different apples among n of them and modulo it with MMis 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 kdifferent 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)%M,其中M=(m0*m2*…*m(k-1)),mi为素数。

AC code:
#include<iostream>#include<algorithm>#include<cstring>#include<cstdio>#include<cmath>#include<queue>#include<map>#include<stack>#include<vector>#define LL long long#define MAXN 1000010using namespace std;const  int N=20;//模方程数 LL a[N],mod[N];LL mul(LL a,LL b,LL mod)//a*b%mod{LL ans=0;while(b){if(b&1)ans=(ans+a)%mod;b>>=1;a=(a+a)%mod;}return ans;}LL quick_mod(LL a,LL b,LL m)//a^b%m {LL ans=1;a%=m;while(b){if(b&1){ans=ans*a%m;}b>>=1;a=a*a%m;}return ans;}LL getC(LL n,LL m,int cur)//C(n,m)%mod[cur]{LL p=mod[cur];if(m>n)return 0;if(m>n-m)m=n-m;LL ans=1;for(int i=1;i<=m;i++){LL a=(n+i-m)%p;LL b=i%p;//ans=mul(ans,mul(a,quick_mod(b,p-2,p),p),p);//p为素数,i对p的逆元可以不用扩张欧几里得进行求解  re=i^(P-2) ans = ans * (a * quick_mod(b, p-2,p) % p) % p;  }return ans; }LL Lucas(LL n,LL k,int cur)//求C(n,k)%mod[cur] {LL p=mod[cur];if(k==0)return 1%p;//return getC(n%p,k%p,cur)*Lucas(n/p,k/p,cur)%p;return getC(n % p, k % p,cur) * Lucas(n / p, k / p,cur) % p;  }void extend_Euclid(LL a,LL b,LL &x,LL &y){if(b==0){x=1;y=0;return;}extend_Euclid(b,a%b,x,y);LL tmp=x;x=y;y=tmp-a/b*y;}LL CRT(LL a[],LL m[],int k)//求C(n,m)%M,其中M=(m0*m2*…*m(k-1)),mi为素数,则先用a[i]存储模方程C(n,m)%mi,{                           //m[]存储所有素数因子mi,k表示总共有k个模方程,返回C(n,m)%M的值 LL M=1;LL ans=0;for(int i=0;i<k;i++)M*=mod[i];for(int i=0;i<k;i++){LL x,y,tmp;LL Mi=M/m[i];extend_Euclid(Mi,m[i],x,y);if(x<0){x=-x;tmp=mul(Mi,x,M);tmp=mul(tmp,a[i],M);tmp=-tmp;}else{tmp=mul(Mi,x,M);tmp=mul(tmp,a[i],M);}ans=(ans+tmp)%M;}while(ans<0)ans+=M;return ans;}int main(){//freopen("D:\\in.txt","r",stdin);int T;scanf("%d",&T);while(T--){LL n,m;int k;scanf("%lld%lld%d",&n,&m,&k);//k=1;for(int i=0;i<k;i++)scanf("%lld",&mod[i]);for(int i=0;i<k;i++)a[i]=Lucas(n,m,i)%mod[i];//printf("%I64d\n",a[0]);printf("%lld\n",CRT(a,mod,k)); }  return 0;}


0 0