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

由于计算机底层设计的原因,做加法往往比乘法快的多,因此将乘法转换为加法计算将会大大提高(大数,比较小的数也没必要)乘法运算的速度,除此之外,当我们计算a*b%mod的时候,往往较大的数计算a*b会超出long long int的范围,这个时候使用快速乘法方法也能解决上述问题.

ps:用中国剩余定理+快速乘时

 ll tmp=qmult(x,Mi,M);只能写成 x*Mi 而 Mi*x 还有写成下面的样子都会错...
 tmp=qmult(tmp,a[i],M);
 //ll tmp=qmult(a[i],Mi,M);
 //tmp=qmult(tmp,x,M);

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define ll long long

using namespace std;

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

ll qmult(ll a,ll b,ll mod)
{
    ll ans=0;
    while(b)
    {
        if(b&1)
        {
            ans=(ans+a)%mod;
        }
        b=b/2;
        a=(a+a)%mod;
    }
    return ans;
}

ll inv(ll num,ll mod)
{
    ll x,y;
    exgcd(num,mod,x,y);
    return (x%mod+mod)%mod;
}

ll com(ll n,ll m,ll mod)
{
    if(n<m) return 0;
    else if(n==m) return 1;
    ll t1=1;
    ll t2=1;
    for(ll i=1;i<=m;i++)
    {
        t1=((t1%mod)*(i%mod))%mod;
        t2=((t2%mod)*((n-i+1)%mod))%mod;
    }
    return qmult(t2,inv(t1,mod),mod);
}

ll Lucas(ll n,ll m,ll mod)
{
    if(m==0) return 1;
    else return qmult(com(n%mod,m%mod,mod),Lucas(n/mod,m/mod,mod),mod);
}

ll CRT(ll a[],ll m[],ll n)
{
    ll M=1;
    ll ans=0;
    for(int i=0;i<n;i++)
    {
        M=M*m[i];
    }
    for(int i=0;i<n;i++)
    {
        ll Mi;
        Mi=M/m[i];
        ll x,y;
        exgcd(Mi,m[i],x,y);
        ll tmp=qmult(x,Mi,M);
        tmp=qmult(tmp,a[i],M);
        //ll tmp=qmult(a[i],Mi,M);
        //tmp=qmult(tmp,x,M);
        ans=(ans+tmp)%M;
    }
    return (ans%M+M)%M;
}

int main(int argc, char const *argv[])
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ll n,m,k;
        scanf("%lld %lld %lld",&n,&m,&k);
        ll a[15],b[15];
        for(int i=0;i<k;i++)
        {
            scanf("%lld",&b[i]);
            a[i]=Lucas(n,m,b[i]);
        }
        ll ans=CRT(a,b,k);
        printf("%lld\n",ans  );
    }
    return 0;
}
时间: 2024-10-19 02:40:38

hdu 5446 Unknown Treasure (Lucas定理+中国剩余定理+快速乘)的相关文章

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

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和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 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+中国剩余定理)

题目地址: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定理+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

hdu 5446(2015长春网络赛J题 Lucas定理+中国剩余定理)

题意:M=p1*p2*...pk:求C(n,m)%M,pi小于10^5,n,m,M都是小于10^18. pi为质数 M不一定是质数 所以只能用Lucas定理求k次 C(n,m)%Pi最后会得到一个同余方程组x≡B[0](mod p[0])x≡B[1](mod p[1])x≡B[2](mod p[2])......解这个同余方程组 用中国剩余定理 Sample Input19 5 23 5 Sample Output6 1 # include <iostream> 2 # include <

hdu 5446 Unknown Treasure 卢卡斯+中国剩余定理

Unknown Treasure Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Problem Description On the way to the next secret treasure hiding place, the mathematician discovered a cave unknown to the map. The mathematician