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;
}

  

时间: 2024-08-07 16:55:35

Lucas+中国剩余定理 HDOJ 5446 Unknown Treasure的相关文章

HDU 5446 Unknown Treasure(lucas + 中国剩余定理 + 模拟乘法)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5446 题目大意:求C(n, m) % M, 其中M为不同素数的乘积,即M=p1*p2*...*pk, 1≤k≤10.1≤m≤n≤10^18. 分析: 如果M是素数,则可以直接用lucas定理来做,但是M不是素数,而是素数的连乘积.令C(n, m)为 X ,则可以利用lucas定理分别计算出 X%p1,X%p2, ... , X % pk的值,然后用中国剩余定理来组合得到所求结果. 比较坑的地方是,

Hdu 5446 Unknown Treasure(Lucas+中国剩余定理)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=5446 思路:Lucas求出所有a[i]=C(n,m)%m[i],中国剩余定理求出最终结果x (LL*LL会爆掉,手写乘法). 中国剩余定理: 设m1,m2,....mn是两两互质的正整数,对任意给定的整数a1,a2,....an必存在整数,满足 x≡a1 (mod m1),x≡a2 (mod m2),x≡a3 (mod m3)...... 并且满足上列方程组的解x(mod m1m2m3.....mn

hdu 5446 Unknown Treasure 中国剩余定理+lucas

题目链接 求C(n, m)%p的值, n, m<=1e18, p = p1*p2*...pk. pi是质数. 先求出C(n, m)%pi的值, 然后这就是一个同余的式子. 用中国剩余定理求解. #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; #define l

hdu 5446 Unknown Treasure (Lucas定理+中国剩余定理+快速乘)

题意:c( n, m)%M    M = P1 * P2 * ......* Pk (其中Pk是素数) 思路:Lucas定理中C(n,m)%M,M必须是素数,当M不是素数时,我们可以把它拆成素数的乘积 如果x=C(n,m)%M ,M=p1*p2*..*pk;  a[i]=Lucas(n,m)%pi: xΞa[1](mod p1) xΞa[2](mod p2) ... xΞa[k](mod pk) 用中国剩余定理就可以把x求出来 注意到这道题ll*ll 由于计算机底层设计的原因,做加法往往比乘法快

HDU 6446 Unknown Treasure Lucas+中国剩余定理+按位乘

HDU 6446 Unknown Treasure 题意:求C(n, m) %(p[1] * p[2] ··· p[k])     0< n,m < 1018 思路:这题基本上算是模版题了,Lucas定理求C(n,m),再用中国剩余定理合并模方程,因为LL相乘会越界,所以用到按位乘. 1 #include <iostream> 2 #include <cstdio> 3 #include <fstream> 4 #include <algorithm&

hdu 5446 Unknown Treasure lucas和CRT

Unknown Treasure Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5446 Description On the way to the next secret treasure hiding place, the mathematician discovered a cave unknown to the map. The mathematician ent

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

Unknown Treasure Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 2209    Accepted Submission(s): 821 Problem Description On the way to the next secret treasure hiding place, the mathematician

【HDOJ】5446 Unknown Treasure

1. 题目描述题目很简单,就是求$C(n,m) % M$. 2. 基本思路这是一道应用了众多初等数论定理的题目,因为数据范围较大因此使用Lucas求$C(n,m) % P$.而M较大,因此通过$a[i] = C(n,m)%P_i$再综合中国剩余定理可解.由于数据可能为$10^{18}$,再进行乘法可能超long long.因此,还需要模拟乘法. 3. 代码 1 /* 5446 */ 2 #include <iostream> 3 #include <sstream> 4 #incl

HDU 5446 Unknown Treasure(Lucas定理+CRT)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5446 [题目大意] 给出一个合数M的每一个质因子,同时给出n,m,求C(n,m)%M. [题解] 首先我们可以用Lucas定理求出对答案对每个质因子的模,然后我们发现只要求解这个同余方程组就可以得到答案,所以我们用中国剩余定理解决剩下的问题. [代码] #include <cstdio> #include <cstring> #include <algorithm> u