hdoj-5446-Unknown Treasure

来源:互联网 发布:手机拍电影特效软件 编辑:程序博客网 时间:2024/05/19 15:19

Problem Description
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 m different apples among n of them and modulo it with M. M is the product of several different primes.

Input
On the first line there is an integer 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) on a line where k is the number of primes. Following on the next line are k different primes p1,…,pk. It is guaranteed that M=p1⋅p2⋅⋅⋅pk≤1018 and pi≤105 for every i∈{1,…,k}.

Output
For each test case output the correct combination on a line.

Sample Input

1
9 5 2
3 5

Sample Output

6

题意:给你n,m,num,然后给你num个数,k1,k2….,knum,然后让你求C(n,m)%(k1*k2*….*knum)
题解:lucas+中国剩余定理裸题,注意在中国剩余定理里面,有可能两数相乘爆long long,要用按位乘的方式,但是这样的话exgcd返回值如果是负数就会出错,所以乘之前要取模成正的。
首先,C(n,m)%k我们是会求的,大概这部分子问题是一个很经典的题目。
假设你会求了,那么我们就可以由此得到num个答案,是%k1,k2,k3….knum后得到的值
然后我们就可以看出就是类似韩信点兵一样的题,三个人一组剩了2个,五个人一组剩了2个这种……
这时候,就用中国剩余定理处理处理就好了
注意ll*ll会爆,所以得手写个快速乘法

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long ll;const int maxn = 1e5 + 5;ll fac[maxn], inv[maxn];ll pow_mod(ll a, int n, int mod){    ll ret = 1;    while (n) {        if (n&1) ret = ret * a % mod;        a = a * a % mod;        n >>= 1;    }    return ret;}void init(int n){    fac[0] = 1;    for (int i = 1; i < n; i++) fac[i] = fac[i-1] * i % n;    inv[n-1] = pow_mod(fac[n-1], n-2, n);    for (int i = n - 2; i >= 0; i--) inv[i] = inv[i+1] * (i+1) % n;}ll C (int n, int m, int mod) {    if (m > n || m < 0 || n < 0) return 0;    return fac[n] * inv[m] % mod * inv[n-m] % mod;}ll lucas(ll n, ll m, int mod){    if (m == 0) return 1;    return lucas(n / mod, m / mod, mod) * C(n % mod, m % mod, mod) % mod;}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 china(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 cas, k;    ll n, m, a[15], p[15];    scanf("%d", &cas);    while (cas--) {        scanf("%lld%lld%d", &n, &m, &k);        for (int i = 0; i < k; i++) {            scanf("%lld", &p[i]);            init(p[i]);            a[i] = lucas(n, m, p[i]);        }        printf("%lld\n", china(k, a, p));    }    return 0;}
0 0