您的位置:首页 > 其它

Unknown Treasure ————(hdu5446) 中国剩余定理+卢卡斯定理

2017-06-08 20:44 447 查看
On the way to the next secret treasure hiding place, the mathematician discovered a cave unknown to the map. The mathematician entered the cave because it is there. Somewhere deep in the cave, she found a treasure chest with a combination
lock and some numbers on it. After quite a research, the mathematician found out that the correct combination to the lock would be obtained by calculating how many ways are there to pick mm different
apples among nn of
them and modulo it with MM. MM is
the product of several different primes.

InputOn the first line there is an integer T(T≤20)T(T≤20) representing
the number of test cases. 

Each test case starts with three integers n,m,k(1≤m≤n≤1018,1≤k≤10)n,m,k(1≤m≤n≤1018,1≤k≤10) on
a line where kk is
the number of primes. Following on the next line are kk different
primes p1,...,pkp1,...,pk.
It is guaranteed that M=p1⋅p2⋅⋅⋅pk≤1018M=p1·p2···pk≤1018 and pi≤105pi≤105 for
everyi∈{1,...,k}i∈{1,...,k}.
OutputFor each test case output the correct combination on a line.
Sample Input
1
9 5 2
3 5


Sample Output
6

题意:给n,m,k,再给出k个素数,求组合数C(n,m)对k个素数的乘积取余
由于数据很大 求组合数要用卢卡斯定理,因为k个数都是素数,所以分别求出对这k个数取余的结果,在用中国剩余定理一合并就好了,注意,中国剩余定理合并的时候有可能爆longlong

#include <iostream>

#include <cstdio>

#include <cstring>

typedef long long LL;

using namespace std;

LL exp_mod(LL a, LL b, LL p) {

    LL res = 1;

    while(b != 0) {

        if(b&1) res = (res * a) % p;

        a = (a*a) % p;

        b >>= 1;

    }

    return res;

}

LL Comb(LL a, LL b, LL p) {

    if(a < b)   return 0;

    if(a == b)  return 1;

    if(b > a - b)   b = a - b;

    LL ans = 1, ca = 1, cb = 1;

    for(LL i = 0; i < b; ++i) {

        ca = (ca * (a - i))%p;

        cb = (cb * (b - i))%p;

    }

    ans = (ca*exp_mod(cb, p - 2, p)) % p;

    return ans;

}

LL Lucas(LL n, LL m, LL p) {

     LL ans = 1;

     while(n&&m&&ans) {

        ans = (ans*Comb(n%p, m%p, p)) % p;

        n /= p;

        m /= p;

     }

     return ans;

}

LL exgcd(LL a, LL b, LL& x, LL& y) {
if (b == 0) { x = 1; y = 0; return a; }
LL d = exgcd(b, a % b, y, x);
y -= x * (a / b);
return d;

}

LL mul(LL a, LL b, LL mod) {
a = (a % mod + mod) % mod;
b = (b % mod + mod) % mod;

LL ret = 0;
while(b){
if(b&1){
ret += a;
if(ret >= mod) ret -= mod;
}
b >>= 1;
a <<= 1;
if(a >= mod) a -= mod;
}
return ret;

}

LL CRT(int n, LL* a, LL* m) {
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];
exgcd(m[i], w, d, y);
x = (x + mul(mul(y, w, M), a[i], M));
}
return (x + M) % M;

}

int main() {

    int T,k;

    LL  n, m;

    LL a[15],b[15];

    scanf("%d",&T);

    while(T--)

    {

        memset(a,0,sizeof(a));

        memset(b,0,sizeof(b));

        cin>>n>>m>>k;

        for(int i=0;i<k;i++)

        {

            cin>>a[i];

            b[i]=Lucas(n,m,a[i]);

        }

        printf("%lld\n",CRT(k,b,a));

    }

    return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: