Lucas+中国剩余定理 HDOJ 5446 Unknown Treasure

 

题目传送门

题意:很裸,就是求C (n, m) % (p1 * p2 * p3 * .... * pk)

分析:首先n,m<= 1e18, 要用到Lucas定理求大组合数取模,当然p[]的乘积<=1e18不能直接计算,但是pi<=1e5。接下来要知道中国剩余定理,所以先对每个pi计算出bi,注意在中国剩余定理的两数相乘会爆long long,所以用乘法取模,"但是这样的话exgcd返回值如果是负数就会出错,所以乘之前要取模成正的",这句话不是很懂。

收获:老祖宗的智慧结晶一定要学

 

代码:

/************************************************
* Author        :Running_Time
* Created Time  :2015/9/15 星期二 13:40:41
* File Name     :J.cpp
 ************************************************/

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
using namespace std;

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
ll f[N];
 
void init(int p) {
    f[0] = 1;
    for (int i=1; i<=p; ++i) f[i] = f[i-1] * i % p;
}
 
ll pow_mod(ll a, ll x, ll p) {
    ll ret = 1;
    while (x)   {
        if (x & 1)  ret = ret * a % p;
        a = a * a % p;
        x >>= 1;
    }
    return ret;
}
 
ll Lucas(ll n, ll k, ll p) {       //C (n, k) % p
     ll ret = 1;
     while (n && k) {
        ll nn = n % p, kk = k % p;
        if (nn < kk) return 0;
        ret = ret * f[nn] * pow_mod (f[kk] * f[nn-kk] % p, p - 2, p) % p;
        n /= p, k /= p;
     }
     return ret;
}

ll multi_mod(ll a, ll b, ll p)    {     //a * b % p
    a = (a % p + p) % p;
    b = (b % p + p) % p;
    ll ret = 0;
    while (b)   {
        if (b & 1)  {
            ret += a;
            if (ret >= p)   ret -= p;
        }
        b >>= 1;
        a <<= 1;
        if (a >= p) a -= p;
    }
    return ret;
}

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, y, x);
    y -= x * (a / b);
    return d;
}

ll China(int k, ll *b, ll *m) {
    ll M = 1, x, y, ret = 0;
    for (int i=1; i<=k; ++i)    M *= m[i];
    for (int i=1; i<=k; ++i)    {
        ll w = M / m[i];
        ex_GCD (w, m[i], x, y);
        ret += multi_mod (multi_mod (x, w, M), b[i], M);
    }
    return (ret + M) % M;
}

int main(void)    {
    int T;  scanf ("%d", &T);
    while (T--) {
        ll p[11], b[11];
        ll n, m;    int k;   scanf ("%I64d%I64d%d", &n, &m, &k);
        for (int i=1; i<=k; ++i)    {
            scanf ("%I64d", &p[i]);   init (p[i]);
            b[i] = Lucas (n, m, p[i]);
        }
        printf ("%I64d\n", China (k, b, p));
    }

    return 0;
}

  

posted @ 2015-09-15 15:42  Running_Time  阅读(225)  评论(0编辑  收藏  举报