HDU 5446 Unknown Treasure (lucas + 中国剩余定理)
题意:计算C(n,m)%(M1*M2*M3......*Mn) 其中Mi是互不相同的素数
分析:如果是C(n,m)%素数 我们直接使用lucas, 但是现在的模是多个素数相乘,所以我们需要配合中国剩余定理,先使用lucas对每一个Mi进行取模运算,保留结果,最后使用中国剩余定理
代码:
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
//#define mod 1000000007
#define lowbit(x) (x&(-x))
#define mem(a) memset(a,0,sizeof(a))
#define FRER() freopen("in.txt","r",stdin);
#define FREW() freopen("out.txt","w",stdout);
using namespace std;
typedef pair<int,int> pii;
const int maxn = 100000 + 7 , inf = 0x3f3f3f3f ;
ll inv[maxn],fac[maxn];
ll p[15],an[15];
ll q_pow(ll a,ll n,ll mod){
ll res = 1;
while(n){
if(n&1) res = res * a %mod;
a = a * a % mod;
n >>= 1;
}
return res;
}
void ini(ll x){
fac[0] = 1;
for(ll i = 1 ; i < x ; i ++) fac[i] = fac[i-1]*i%x;
inv[x-1] = q_pow(fac[x-1],x-2,x);
for(ll i = x-2 ; i >= 0;i--) inv[i] = inv[i+1]*(i+1)%x;
}
ll C(ll a,ll b,ll p){
if(a<b||a<0||b<0) return 0;
return fac[a]*inv[b]%p*inv[a-b]%p;
}
ll ex_gcd(ll a,ll b,ll &x,ll &y){
if(b == 0){
x = 1;
y = 0;
return a;
}
ll d = ex_gcd(b,a%b,x,y);
ll tmp = x;
x = y;
y = tmp - (a / b)*y;
}
ll lucas(ll a,ll b,int p){
if(b==0)
return 1;
return lucas(a/p,b/p,p)*C(a%p,b%p,p)%p;
}
ll mul(ll a,ll b,ll mod){
a = (a%mod+mod)%mod;
b = (b%mod+mod)%mod;
ll res = 0;
while(b){
if(b&1){
res += a;
if(res>=mod) res-=mod;
}
b >>= 1;
a <<= 1;
if(a >= mod) a -=mod;
}
return res;
}
ll CRT(ll n,ll *a,ll *m){
ll M = 1 , res = 0;
for(ll i=0;i<n;i++)
M *= m[i];
for(ll i=0;i<n;i++){
ll Mi = M/m[i];
ll x,y;
ex_gcd(Mi,m[i],x,y);
res = (res + mul(mul(x,Mi,M),a[i],M));
}
return (res+M)%M;
}
int main(){
//FRER();
//FREW();
ll T,k;
ll n,m;
scanf("%lld",&T);
while(T--){
scanf("%lld%lld",&n,&m);
scanf("%lld",&k);
for(ll i=0;i<k;i++){
scanf("%lld",&p[i]);
ini(p[i]);
an[i] = lucas(n,m,p[i]);
}
printf("%lld\n",CRT(k,an,p));
}
}