zoukankan      html  css  js  c++  java
  • gcd以及exgcd入门讲解

    gcd就是最大公约数,gcd(x, y)一般用(x, y)表示。与此相对的是lcm,最小公倍数,lcm(x, y)一般用[x, y]表示。

    人人都知道:lcm(x, y) = x * y / gcd(x, y)

    证明起来也不是很难:

    (这真的是我自己写的,因为博客园不支持这格式……)

    至于gcd的求法,想必各位在高中都学过辗转相除法和更相减损之术,这里只讲辗转相除法(更相减损之术略慢)

    首先不妨设 x ≤ y,则gcd(x, y)  =gcd(x, x +y) = gcd(x, y - x).所以gcd(x, y) = gcd(y % x, x),因此可以递归求解。

    复杂度证明:因为y % x ≤ x && x ≤ y,所以y % x < y / 2。因此在最坏情况下为O(nlogn)。(用斐波那契数列的相邻两个数可以达到最坏复杂度)

    那么接下来讲一下扩展gcd。

    exgcd可以用来判断并求解形如ax +by = c 的方程,当且仅当gcd(a, b) | c时,存在整数解x, y。

    也就是说,exgcd可以用来求解方程ax +by = gcd(a, b)

    令a = b, b = a % b,则有方程b *x1 +(a % b) * y1 = gcd(b, a % b)

    又因为gcd(a, b) = gcd(a % b),且a % b = a - b * ⌊a / b⌋

    则b * x1 + (a - b * ⌊a / b⌋) * y1  =gcd(a, b)

    整理得:a * y1 +b * (x1 - ⌊a / b⌋ *y1) = gcd(a, b)

    所以原方程中:x = y1, y = x1 - ⌊a / b⌋ *y1。于是我们只要递归求出x1, y1就能求出x, y。

    代码很短

    1 void exgcd(ll a, ll b, ll& x, ll& y, ll& c)
    2 {
    3     if(!b) {y = 0; x = 1; c = a; return;}
    4     exgcd(b, a % b, y, x); y -= a / b * x;
    5 }

    其中c = gcd(a, b)

    值得注意的是,递归调用的时候y的位置上传了x,x位置上是y,也就是说,y里存的是x1,x里存的是y1,所以y -= a / b *y1,即y -= a / b * x。

    我们现在已经求得了ax +by = gcd(a, b)的解,那么对于方程ax + by = c (gcd(a, b) | c)呢?

    因为已经知道a *x1 +b * y1 = gcd(a, b)的解x1, y1,左右两边同乘以c / gcd(a, b) 得:

    a * x1 * c / gcd(a, b) +b * y1 * c / gcd(a, b) = c

    则原方程的一组解x2 = x1 * c / gcd(a, b), y2 = y1 * c / gcd(a, b)

    由此得出解集{(x, y) | x = x2 + k * b / gcd(a, b), y = y2 - k * a / gcd(a, b), k ∈ z}

  • 相关阅读:
    LSB最低有效位和MSB最高有效位
    STM32(十二)通过I2C总线向EEPROM总线中读写数据的过程
    EEPROM和Flash的区别
    Prometheus监控系统的从无到有
    shell 提取第一个指定参数前面的内容
    myBase7试用到期 破解步骤
    docker入门(六)端口映射于容器关联
    docker入门(五)docker数据管理
    针对ansible的一次调研
    docker入门(四)访问docker仓库
  • 原文地址:https://www.cnblogs.com/mrclr/p/9380300.html
Copyright © 2011-2022 走看看