码迷,mamicode.com
首页 > 其他好文 > 详细

ACM学习历程—HDU 5446 Unknown Treasure(数论)(2015长春网赛1010题)

时间:2015-09-14 22:20:00      阅读:222      评论:0      收藏:0      [点我收藏+]

标签:

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 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(T20) representing the number of test cases.

Each test case starts with three integers n,m,k(1mn10^18,1k10) 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=p1p2pk10^18 and pi10^5 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

 

题目要求一个大组合数模几个素数乘积的结果。

大组合那块能通过Lucas得到对每个素数模的结果。

然后再通过互质型的中国剩余定理可以得到最终结果。

不过我的模板中国剩余定理里面乘法部分会爆long long。

然后用大数优化了乘法部分,通过大数乘大数,模完后返回小数。

 

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#define LL long long
#define UNIT 10

using namespace std;

const int maxK = 15;
LL n, m, s[maxK], prime[maxK];
int k;

struct Bignum
{
    int val[105];
    int len;

    Bignum()
    {
        memset(val, 0, sizeof(val));
        len = 1;
    }

    Bignum operator=(const LL &a)
    {
        LL t, p = a;
        len = 0;
        while (p >= UNIT)
        {
            t = p - (p/UNIT)*UNIT;
            p = p / UNIT;
            val[len++] = t;
        }
        val[len++] = p;
        return *this;
    }

    Bignum operator*(const Bignum &a) const
    {
        Bignum x;
        int i, j, up;
        int x1, x2;
        for (i = 0; i < len; i++)
        {
            up = 0;
            for (j = 0; j < a.len; j++)
            {
                x1 = val[i]*a.val[j] + x.val[i+j] + up;
                if (x1 >= UNIT)
                {
                    x2 = x1 - x1/UNIT*UNIT;
                    up = x1 / UNIT;
                    x.val[i+j] = x2;
                }
                else
                {
                    up = 0;
                    x.val[i+j] = x1;
                }
            }
            if (up != 0)
                x.val[i+j] = up;
        }
        x.len = i + j;
        while (x.val[x.len-1] == 0 && x.len > 1)
            x.len--;
        return x;
    }

    LL operator%(const LL &a) const
    {
        LL x = 0;
        for (int i = len-1; i >= 0; --i)
            x = ((x*UNIT)%a+val[i]) % a;
        return x;
    }
};

LL mulMod(LL x, LL y, LL p)
{
    LL ans = 0;
    Bignum xx, yy;
    xx = x;
    yy = y;
    xx = xx*yy;
    ans = xx%p;
    return ans;
}

LL quickMod(LL a, LL b, LL p)
{
    LL ans = 1;
    a %= p;
    while (b)
    {
        if (b&1)
        {
            ans = ans*a%p;
            b--;
        }
        b >>= 1;
        a = a*a%p;
    }
    return ans;
}

LL C(LL n, LL m, LL p)
{
    if (m > n)
        return 0;
    LL ans = 1;
    for(int i = 1; i <= m; i++)
    {
        LL a = (n+i-m)%p;
        LL b = i%p;
        ans = ans*(a*quickMod(b, p-2, p)%p)%p;
    }
    return ans;
}

LL Lucas(LL x, LL y, LL p)
{
    if (y == 0)
        return 1;
    return C(x%p, y%p, p)*Lucas(x/p, y/p, p)%p;
}

//EXGCD
//求解方程ax+by=d,即ax=d mod(b)
//扩展可求逆元
//O(logn)
void exgcd(LL a, LL b, LL &x, LL &y, LL &d)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        d = a;
    }
    else
    {
        exgcd(b, a%b, y, x, d);
        y -= a/b*x;
    }
}

//中国剩余定理(互质)
//其中a为除数数组,n为模数数组
LL CRT(LL *a, LL *n, int len)
{
    LL N = 1, ans = 0;
    for (int i = 0; i < len; i++)
    {
        N *= n[i];
    }
    for (int i = 0; i < len; i++)
    {
        LL m = N / n[i];
        LL x, y, d;
        exgcd(m, n[i], x, y, d);
        x = (x%n[i] + n[i]) % n[i];
        //ans = (ans + m*a[i]*x%N) % N;
        ans = (ans + mulMod(mulMod(m, a[i], N), x, N)) % N;
    }
    return ans;
}

void input()
{
    scanf("%I64d%I64d%d", &n, &m, &k);
    for (int i = 0; i < k; ++i)
        scanf("%I64d", &prime[i]);
}

void work()
{
    for (int i = 0; i < k; ++i)
        s[i] = Lucas(n, m, prime[i]);
    LL ans = CRT(s, prime, k);
    printf("%I64d\n", ans);
}

int main()
{
    //freopen("test.in", "r", stdin);
    int T;
    scanf("%d", &T);
    for (int times = 0; times < T; ++times)
    {
        input();
        work();
    }
    return 0;
}

 

ACM学习历程—HDU 5446 Unknown Treasure(数论)(2015长春网赛1010题)

标签:

原文地址:http://www.cnblogs.com/andyqsmart/p/4808191.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!