前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >拓展欧几里德算法(exgcd)学习笔记

拓展欧几里德算法(exgcd)学习笔记

作者头像
Clouder0
发布2022-09-23 11:54:06
4970
发布2022-09-23 11:54:06
举报
文章被收录于专栏:Coding Is FunCoding Is Fun

拓展欧几里得算法

解不定方程 ax + by = c ,可以使用拓展欧几里得算法。

首先解 ax + by = \gcd (a,b) .

欧几里得算法

证明 \gcd(a,b) = \gcd(b,a \bmod b)

a = g \times k_1b = g \times k_2 ,其中 k_1,k_2 互质。

要证明 \gcd(a,b) = \gcd(b,a\bmod b) ,即证 g = \gcd(g \times k_2, (g \times k_1 )\bmod (g \times k_2)) .

g 消去,即证 \gcd(k_2,k_1 \bmod k_2) = 1 .

假设有公因子 x ,则:

k_2 = x \times n_1k_1 \bmod k_2 = x \times n_2 .

可以写出: k_1 = k \times k_2 + k_1 \bmod k_2 ,其中 k 为整数。

化简得出: k_1 = k \times (x \times n_1) + x \times n_2 ,则 k_1,k_2 有公因子 x ,而 k_1,k_2 应当互质,矛盾。

所以 \gcd(k_2,k_1 \bmod k_2) = 1 .

\gcd(a,b) = \gcd(b,a\bmod b) .

拓展欧几里得算法

证明 ax + by = \gcd(a,b) 一定有解。 (a,b \neq 0) .

由上文结论,该式等价于:

bx + (a \bmod b)y = \gcd(b,a \bmod b) .

辗转相除,当 b = 0 时,方程为: ax = \gcd(a,b) = a ,即用欧几里得算法求最大公因数的最后一步。

x = 1,y = 0 .

向上还原,即可获得一组解。


拓展欧几里得算法用于求出 ax + by = \gcd(a,b) 的一组特解:

ax_1 + by_1 = \gcd(a,b) 可转化为:

bx_2 + (a \bmod b)y_2 = \gcd(b,a \bmod b) .

其中: \gcd(a,b) = \gcd(b,a \bmod b) .

可以得到: ax_1 + by_1 = bx_2 + (a \bmod b)y_2 .

即: ax_1 + by_1 = bx_2 + (a - \lfloor \dfrac{a}{b} \rfloor \times b)y_2 .

展开、合并同类项得到: ax_1 + by_1 = ay_2 + b(x_2 - y_2 \times \lfloor \dfrac{a}{b} \rfloor)

即:

x_1 = y_2y_1 = x_2 - y_2 \times \lfloor \dfrac{a}{b} \rfloor = x_2 - x_1 \times \lfloor \dfrac{a}{b} \rfloor .

可以据此写出拓展欧几里得算法。可以使用引用传值的技巧简化代码。

代码语言:javascript
复制
int exgcd(int a,int b,int &x,int &y)
{
    if(b == 0) 
    {
        x = 1,y = 0;
        return a;
    }
    int g = exgcd(b, a % b, y, x);
    y -= x * (a / b);
    return g;
}


此时回归到解 ax + by = c 的问题上来。若 \gcd(a,b) \mid c ,则原方程有整数解。

ax' + by' = \gcd(a,b) ,则:

x = x' \times \dfrac{c}{\gcd(a,b)}
y = y' \times \dfrac{c}{\gcd(a,b)}

若要得到任意组解呢?

记求出的特解为 x_0,y_0 .

ax + by = ax_0 + by_0 .

a(x - x_0) = b(y_0-y) .

\dfrac{a}{b} \times (x - x_0) = y_0 - y .

x - x_0 需要为整数,则 \dfrac{b}{\gcd(a,b)} \mid (x' - x_0') ,设为 x' - x_0' = \dfrac{b}{\gcd(a,b)} \times t .

可以写出:

x' = x_0' + \dfrac{b}{\gcd(a,b)} \times t

y' = y_0' - \dfrac{a}{\gcd(a,b)} \times t

由此即可求出任意解,再带回原式即可。

例如求 x' 的最小正整数解,可以发现 x' 任意加减 b 都是合法解,因此可以直接 ((x \bmod b) + b) \bmod b .


拓展欧几里得算法还可以用于求解线性同余方程。

形如 ax \equiv c \pmod{b} .

可以写成 ax + by = c ,随后按二元一次不定方程的方法求解即可。


例题:青蛙的约会

两只青蛙初始坐标为 x,y ,每次跳 m,n 米,定义相遇为模 L 意义下坐标相等,求一起跳跃多少次后相遇。

形式地, x + m \times t = y + n \times t \pmod L .

x + m \times t + L \times k = y + n \times t
(m-n) \times t + L \times k = y - x

t 的最小正整数解。

套上板子即可。

代码语言:javascript
复制
#include <algorithm>
#include <cstdio>
#define ll long long
ll sx, sy, m, n, L;
inline ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
inline void exgcd(ll a, ll b, ll& x, ll& y)
{
    if (b == 0) return (void)(x = 1, y = 0);
    exgcd(b, a % b, y, x), y -= (a / b) * x;
}
int main()
{
    scanf("%lld %lld %lld %lld %lld", &sx, &sy, &m, &n, &L);
    if(m - n < 0) std::swap(m,n),std::swap(sx,sy);
    ll g = gcd(m - n, L);
    ll a = m - n, b = L, x, y, c = sy - sx;
    if (c % g) { puts("Impossible"); return 0; }
    exgcd(a, b, x, y);
    x *= c / g, y *= c / g;
    ll mod = b / g;
    x = ((x % mod) + mod) % mod;
    printf("%lld\n", x);
    return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 拓展欧几里得算法
    • 欧几里得算法
      • 拓展欧几里得算法
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档