扩展欧几里得
定义
扩展欧几里得算法是欧几里得算法(又叫辗转相除法)的扩展。已知整数\(a,b\),扩展欧几里得算法可以在求得a、b的最大公约数的同时,能找到整数x、y(其中一个很可能是负数),使他们满足等式:\(ax+by=gcd(a,b)\)
问题
已知\(a,b\),求满足\(ax+by=gcd(a,b)\)的整数 \(x\) 与 \(y\)。其中 \(x\) 应当是满足条件的最小正整数,\(y\) 是辅助答案。
解
由欧几里得算法知
\[\gcd(a,b)=\gcd(b,a \bmod b)
\]
如果现在存在\(x_2,y_2\)使得
\[bx_2 + (a \bmod b)y_2 = gcd(b, a \bmod b)
\]
那么会有
\[ax + by = bx_2 + (a \bmod b)y_2
\]
\[\Downarrow
\]
\[ax + by = bx_2 + (a-b×(a/b))y_2
\]
\[\Downarrow
\]
\[ax + by = bx_2 + ay_2 - b × (a/b)y_2
\]
\[\Downarrow
\]
\[ax + by = ay_2 + b(x_2-(a/b)y_2)
\]
此时得到一组显然解
\[\begin{cases}x = y_2\\y = x_2-(a/b)y_2\end{cases}
\]
容易想到:可以采取递归的方法,重复这个过程直至普通欧几里得算法的递归基即
\[b = 0
\]
此时易知使得\(ax_n+by_n=gcd(a,b)\)成立即
\[\begin{cases}x_n = 1\\y_n = 0\end{cases}
\]
在回溯过程中可计算得到所求\(x,y\)
解的处理
此时已经求得了一组满足题意的\(x,y\)
但是\(x\)为最小正整数的要求并未满足,此时\(x\)可能偏大或偏小(为负值)
已知\(ax + by = 1\),那么
\[ax + by + k×ba - k×ba = 1
\]
\[\Downarrow
\]
\[a(x+kb) + (y-ka)b = 1
\]
可以看出 \(x\)以 \(b\)的倍数 为变化量变化时,总能满足题意
由\(ax + by = 1\)知 \(\frac{1-ax}{b} = y\)
则 \(1-ax\)是b的倍数
那么要得到符合题意的\(x,y\) 必然要使\(1-ax\)的变化量为\(b\)的倍数
则 \(x\)变化量必然为b的倍数
那么相当于我们证明了
- 在所求\(x\)基础上使\(x\)以\(b\)的倍数为变化量变化,总能得到满足题意的最小正整数\(x\)
代码实现
#include <iostream>
using namespace std;
long long x , y;
void exgcd(long long a , long long b){
//if(a < b) return exgcd(b , a);
if(b == 0){
x = 1 , y = 0;
return;
}
exgcd(b , a % b);
long long tmp = x;
x = y , y = tmp - (a / b) * y;
}
int main(){
long long a , b;
cin >> a >> b;
exgcd(a , b);
while(x < 0) x += b;
x %= b;
cout << x << endl;
}
参考文章:
题解 P1082 【同余方程】
(作者:学委)
Exgcd(作者:samzhang)

浙公网安备 33010602011771号