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));
    }
}

 

posted @ 2018-08-21 21:59  dslybyme7  阅读(122)  评论(0编辑  收藏  举报