• 最大公约数、最小公倍数的两种求法


    目录

    目录地址

    上一篇

    下一篇


    公因数的性质

    对于两个正整数 (a,b) ,若有另外一个正整数 (d) 满足 (dmid a)(dmid b) 则称呼 (d)(a,b) 的公因数

    (a,b) 的所有公因数中,最大的被称呼为最大公因数,我们记为 ((a,b))(gcd(a,b))

    最大公因数在质数分解上的性质

    不妨设 (displaystyle a=p_1^{c_1}p_2^{c_2}p_3^{c_3}cdots p_m^{c_m},b=p_1^{d_1}p_2^{d_2}p_3^{d_3}cdots p_m^{d_m})

    其中, (forall c_i,d_iin N)(c_i>0)(d_i>0)

    (displaystyle gcd(a,b)=p_1^{min(c_1,d_1)}p_2^{min(c_2,d_2)}p_3^{min(c_3,d_3)}cdots p_m^{min(c_m,d_m)})

    先证明必要性:显然,满足这个式子的正整数 (g) 一定有 (gmid a)(gmid b)

    其次证明其充分性:首先,作为 (a,b) 的因数, (g) 不可能含有以上 (m) 个质数以外的质因数

    因此,不妨设 (d=g imes p_i) ,其中, (p_i) 是上面任意一个质数

    再不妨设 (c_i<d_i)

    因此, (min(c_i,d_i)=c_i)

    所以 (d) 中含有 ((c_i+1))(p_i) 质因子

    (d mid a) 不为 (a,b) 公因数

    原命题得证

    最大公因数的因数的性质

    可以证明:所有的公因数 (Leftrightarrow) 最大公因数的所有因数

    证明:

    我们记 (g=gcd(a,b)) 则显然 (gmid a,gmid b) 且不存在 (forall din Z,d>g)(dmid a,dmid b)

    我们先证明必要性:对于所有 (g) 的因数 (c) ,显然有 (cmid g) 。故 (cmid a,cmid b) 。因此 (c)(a,b) 的公因数

    充分性的证明我们考虑将 (g) 按质因数分解:

    (displaystyle a=p_1^{c_1}p_2^{c_2}p_3^{c_3}cdots p_m^{c_m},b=p_1^{d_1}p_2^{d_2}p_3^{d_3}cdots p_m^{d_m})

    其中, (forall c_i,d_iin N)(c_i>0)(d_i>0)

    (displaystyle gcd(a,b)=p_1^{min(c_1,d_1)}p_2^{min(c_2,d_2)}p_3^{min(c_3,d_3)}cdots p_m^{min(c_m,d_m)})

    (dmid a,dmid b) 则若 (d=p_1^{e_1}p_2^{e_2}p_3^{e_3}cdots p_m^{e_m})

    故一定有 (forall e_ileq c_i,e_ileq d_i)

    (e_ileq min(c_i,d_i))

    因此 (dmid g)

    最大公因数的互质性质

    (g=gcd(a,b))(gcd({aover g},{bover g})=1)

    证明:(displaystyle a=p_1^{c_1}p_2^{c_2}p_3^{c_3}cdots p_m^{c_m},b=p_1^{d_1}p_2^{d_2}p_3^{d_3}cdots p_m^{d_m})

    其中, (forall c_i,d_iin N)(c_i>0)(d_i>0)

    (displaystyle gcd(a,b)=p_1^{min(c_1,d_1)}p_2^{min(c_2,d_2)}p_3^{min(c_3,d_3)}cdots p_m^{min(c_m,d_m)})

    ( herefore egin{cases} {aover g}=p_1^{c_1-min(c_1,d_1)}p_2^{c_2-min(c_2,d_2)}p_3^{c_3-min(c_3,d_3)}cdots p_m^{c_m-min(c_m,d_m)} \ \ {bover g}=p_1^{d_1-min(c_1,d_1)}p_2^{d_2-min(c_2,d_2)}p_3^{d_3-min(c_3,d_3)}cdots p_m^{d_m-min(c_m,d_m)} end{cases})

    (displaystyle gcd({aover g},{bover g})=prod_{i=1}^mp_i^{min( c_i-min(c_i,d_i),d_i-min(c_i,d_i) )}=prod_{i=1}^mp_i^{min(c_i,d_i)-min(c_i,d_i)}=prod_{i=1}^mp_i^0=1)


    公倍数的性质

    对于两个正整数 (a,b) ,若有另外一个正整数 (m) 满足 (amid m)(bmid m) 则称呼 (m)(a,b) 的公倍数

    (a,b) 的所有公倍数中,最小的被称呼为最小公倍数,我们记为 ([a,b])(lcm(a,b))

    同上,可以证得:

    1.若 (displaystyle a=p_1^{c_1}p_2^{c_2}p_3^{c_3}cdots p_m^{c_m},b=p_1^{d_1}p_2^{d_2}p_3^{d_3}cdots p_m^{d_m})

    其中, (forall c_i,d_iin N)(c_i>0)(d_i>0)

    (displaystyle lcm(a,b)=p_1^{max(c_1,d_1)}p_2^{max(c_2,d_2)}p_3^{max(c_3,d_3)}cdots p_m^{max(c_m,d_m)})

    2.范围内,所有的公倍数 (Leftrightarrow) 最小公倍数的所有倍数

    额外的,可以证得如何用最大公因数求出最小公倍数:

    (displaystyle a=p_1^{c_1}p_2^{c_2}p_3^{c_3}cdots p_m^{c_m},b=p_1^{d_1}p_2^{d_2}p_3^{d_3}cdots p_m^{d_m})

    其中, (forall c_i,d_iin N)(c_i>0)(d_i>0)

    (displaystyle gcd(a,b)=p_1^{min(c_1,d_1)}p_2^{min(c_2,d_2)}p_3^{min(c_3,d_3)}cdots p_m^{min(c_m,d_m)})

    其次,还有 (displaystyle lcm(a,b)=p_1^{max(c_1,d_1)}p_2^{max(c_2,d_2)}p_3^{max(c_3,d_3)}cdots p_m^{max(c_m,d_m)})

    由于 (max(c_i,d_i)=c_i+d_i-min(c_i,d_i))

    (displaystyle lcm(a,b)=prod_{i=1}^mp_i^{max(c_i,d_i)}=prod_{i=1}^mp_i^{c_i+d_i-min(c_i,d_i)}=prod_{i=1}^mp_i^{c_i}cdot prod_{i=1}^mp_i^{d_i}cdot(prod_{i=1}^mp_i^{min(c_i,d_i)})^{-1}={acdot bover gcd(a,b)})


    更相减损术

    出自《九章算数》,算法过程如下:

    (a eq b) 时,用大数减去小数,再比较这两数

    重复上述操作,直至两数相等

    所得数即为 (a,b) 的最大公因数

    证明一下它的正确性:

    我们在原算法的基础上再添一步: (a=b) 后, (a) 再减去一次 (b) ,此刻 (a=0,b) 为最大公因数

    加上此步后,可以延拓至任意正整数 (n)(0) 的最大公因数都为 (n)

    (g=gcd(a,b),a=Ag,b=Bg)(gcd(A,B)=1)

    (a=b)(A=B)(A=B=1) 此时得到的为最大公因数

    否则不妨设 (A>B) ,则 (a>b)

    (a) 应该减去 (b) ,成为 ((A-B)g)

    若此时 (a) 仍大于 (b) ,则进而成为 ((A-2B)g) ,重复执行后会成为 ((A\%B)g)

    这里的证明过程我们先跳过,避免和下面辗转相除法重复

    可证得,重复执行后,一定能使得较大的变为 (gcd(A,B)cdot g=g) ,较小的变为 (0)

    下面是它的代码实现:

    if(a<b) swap(a,b);
    while(b!=0){
        a-=b;
        if(a<b) swap(a,b);
    }
    

    最坏情况下,输入 (n)(1) ,复杂度为 (O(n))

    优化

    根据《九章算数》:“可半者半之,不可半者,副置分母、子之数,以少减多,更相减损,求其等也。以等数约之。”

    (a,b) 同时为偶数时, (g) 翻倍,且 (a,b) 同时减半

    (a,b) 一个为偶数时,为偶数的减半

    这样既不影响计算,又可以加快运行速度:

    int g=1;
    while(a%2==0&&b%2==0) a/=2,b/=2,g*=2;
    if(a<b) swap(a,b);
    while(b!=0){
        a-=b;
        while(a%2==0&&b%2==0) a/=2,b/=2,g*=2;
        if(a<b) swap(a,b);
    }
    g*=a;
    

    最坏情况下就是 (n=(2^k-1))(1) 时,复杂度 (O(log n))

    当然,还会有其它的优化。由于和后者辗转相除法类似,就放到后面说了


    辗转相除法

    辗转相除法,又名欧几里得算法,由古希腊数学家欧几里得(Euclid)提出

    对于非零的数 (a) 与数 (b) (如果一个为零,另一个直接就是答案)

    (g=gcd(a,b))

    (gmid a,gmid b)

    (a=kb+r,(0leq r<b))

    (r=a\%b)

    又由 (gmid a=gmid(kb+r),gmid bRightarrow gmid kb)(gmid (a-kb)Rightarrow gmid r)

    因此,(gcd(a,b)=gcd(b,a\%b))

    代码实现:

    int gcd(int a,int b){ return b?a:gcd(b,a%b); }
    

    非递归写法:

    while(b!=0){
        int tmp=a%b;
        a=b;
        b=tmp;
    }
    

    考虑到非递归写法的实质是交换 (a,b) 并用交换后的 (b)(a) 取模

    故此可进一步写为:

    while(b!=0){
        swap(a,b);
        b%=a;
    }
    

    又考虑到 swap 函数可以通过 a^=b^=a^=b 实现,且赋值语句返回值为所附值的 C++ 特性

    最终压行为

    if(!b) while(b^=a^=b^=a%=b);
    

    复杂度均为 (O(log n))

    优化

    由于辗转相除法的复杂度已经较低,各个优化方案都只能优化常数

    不过,幸运的是,这些优化方法对更相减损术也适用

    同样用到《九章算术》提到的优化法,并加入二进制实现快速的乘除操作:

    int g=1;
    while(b!=0){
        while( (a&1)==0&&(b&1)==0 ) a>>=1,b>>=1,g<<=1;
        swap(a,b);
        b%=a;
    }
    g*=a;
    

    还可以使用 lowbit 进行优化运算

    其中 (lowbit(x)) 函数,为取数 (x) 的最低二进制位函数

    (lowbit(6)=4,lowbit(34)=2)

    在 C++ 中,可用 (x&(-x)) 实现

    故引入 lowbit 优化运算:

    int g=1;
    while(b!=0){
        g*=Min(a&(-a),b&(-b));
        a/=(a&(-a));
        b/=(b&(-b));
        swap(a,b);
        b%=a;
    }
    g*=a;
    
  • 相关阅读:
    Linux下CPU利用率和负载的关系
    Linux系统中的load average(平均负载/运行队列)
    性能测试分析及调优准备
    解读Loadrunner网页细分图(Web Page Diagnostics)
    LR性能测试分析流程
    【转】多数据源
    【转】BAT启动执行JAVA JAR文件中的MAIN方法的两种方式
    【转】java.net.SocketException
    [webservices]怎样用SoapUI测试接口
    【转】了解webservice
  • 原文地址:https://www.cnblogs.com/JustinRochester/p/12355660.html
Copyright © 2020-2023  润新知