HDU 5446 Unknown Treasure

题意:求C(n,m)%p     p = p1 * p2 *....*pk;

Lucas定理 + 中国剩余定理

http://blog.sina.com.cn/s/blog_12fea76590102w6ts.html

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <set>
#include <queue>
using namespace std;
#define ll long long
const int N = 20;
ll A[N], B[N];
ll q_pow(ll x,ll y, ll p){
    ll ret = 1;
    while(y){
        if(y&1)ret = (ret*x)%p;
        x = (x*x)%p;
        y >>= 1;
    }
    return ret;
}
ll Cm(ll n, ll m, ll p){
    if(n < m)return 0;
    if(n == m)return 1;
    if(m > n-m)m = n-m;
    ll ans = 1, cn = 1, cm = 1;
    while(m){
        cn = (cn * n)%p;
        cm = (cm * m)%p;
        n--,m--;
    }
    ans = (cn * q_pow(cm,p-2,p))%p;
    return ans;
}
ll Lucas(ll n, ll m, ll p){
    if(m == 0)return 1;
    return Cm(n%p,m%p,p) * Lucas(n/p, m/p, p)%p;
}
ll Ex_gcd(ll a, ll b,ll &x, ll &y){
    if(b == 0){
        x = 1;
        y = 0;
        return a;
    }
    ll ret = Ex_gcd(b, a%b, y, x);
    y -= a/b*x;
    return ret;
}
ll multi(ll a,ll b,ll p){
    ll ret = 0;
    while(b){
        if(b&1)ret = (ret + a)%p;
        a = (a+a)%p;
        b>>=1;
    }
    return ret;
}
ll china(ll n, ll *m, ll *a){
    ll M = 1, d, y, x = 0;
    for(int i = 0; i < n; i++){
        M *= m[i];
    }

    for(int i = 0; i < n; i++){
        ll w = M / m[i];
        d = Ex_gcd(m[i], w, d, y);
        //multi(y,w,M) = w*w^-1   (w^-1)为w/m[i]%M的逆元
        x = (x + multi(multi(y, w, M), a[i], M))%M;
    }
    return (x+M)%M;
}
int main(){
    int T, k;
    ll n, m;
    scanf("%d",&T);
    while(T--){
        scanf("%lld%lld%d",&n,&m,&k);
        for(int i = 0; i < k; i++){
            scanf("%lld",A+i);
            B[i] =  Lucas(n, m, A[i]);
        }
        printf("%lld\n",china(k,A,B));
    }
    return 0;
}


你可能感兴趣的:(HDU,中国剩余定理,Lucas定理)