• 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
    ",ans  );
        }
        return 0;
    }
  • 相关阅读:
    结对项目进度1
    学期总结之数学建模软件——LINGO和R
    四则运算计算程序(完成)
    学期总结之数学建模软件——编译原理
    图形学算法之NichollLeeNicholl算法
    学期总结之3D游戏开发
    《构建之法》读后感
    四则运算计算程序(初步)
    结对项目进度2
    Spring IOC原理解析
  • 原文地址:https://www.cnblogs.com/simplekinght/p/7000355.html
Copyright © 2020-2023  润新知