hdu 5446: Unknown Treasure

比较套路的题,对于每个$p$,用$lucas$定理爆算,然后拿$CRT$合并即可。

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
int pri[12];
int fac[100010][12], inv[100010][12];
LL n,m;int k;
inline void init() {
    rep(i,1,k){
        fac[0][i]=1;
        rep(j,1,pri[i]-1){
            fac[j][i]=1ll*fac[j-1][i]*j%pri[i];
        }
        inv[0][i]=inv[1][i]=1;
        rep(j,2,pri[i]-1){
            inv[j][i]=1ll*inv[pri[i]%j][i]*(pri[i]-pri[i]/j)%pri[i];
        }
        rep(j,1,pri[i]-1){
            inv[j][i]=1ll*inv[j-1][i]*inv[j][i]%pri[i];
        }
    }
}
inline int Power(int x,int y,int MOD){
    int ret=1;
    while(y){
        if(y&1)ret=1ll*ret*x%MOD;
        x=1ll*x*x%MOD;y>>=1;
    }
    return ret;
}
inline int C(int x,int y,int p){
    if(x<y)return 0;
    return 1ll*fac[x][p]*inv[x-y][p]%pri[p]*inv[y][p]%pri[p];
}
inline LL lucas(LL x,LL y,LL p){
    if(x<pri[p]&&y<pri[p])return C(x,y,p);
    return lucas(x/pri[p],y/pri[p],p)*lucas(x%pri[p],y%pri[p],p)%pri[p];
}
inline LL mul(LL x,LL y,LL P){
    LL ret=0;
    while(x){
        if(x&1){
            ret+=y;
            if(ret>=P)ret-=P;
        }
        y+=y;
        if(y>=P)y-=P;
        x>>=1;
    }
    return ret;
}
inline void solve(){
    scanf("%lld%lld%d",&n,&m,&k);
    LL P=1;
    rep(i,1,k){
        scanf("%d",&pri[i]);
        P*=pri[i];
    }
    init();
    LL res=0;
    rep(i,1,k){
        LL Mi=P/pri[i],inv_Mi=Power(Mi%pri[i],pri[i]-2,pri[i]);
        LL tmp=lucas(n,m,i);
        tmp=mul(tmp,Mi*inv_Mi,P);
        res+=tmp;
        if(res>=P)res-=P;
    }
    printf("%lld\n",res);
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        solve();
    }
}

 

posted @ 2019-05-30 16:36  iamunstoppable  阅读(206)  评论(0编辑  收藏  举报