先学习前置知识裴蜀(贝祖)定理,戳这里。
还需要学习欧几里得算法(辗转相除法),戳这里
问题
扩展欧几里得算法所解决的问题实际上不是很明确,它更像是一种工具。
在特殊情况下可以通过算法求出和答案所关联的值。
但如果非要说一个,我自己总结了一下:
解决裴蜀定理下给出不变量 a , b a,b a,b,求解 x , y , gcd ( a , b ) x,y,\gcd(a,b) x,y,gcd(a,b) 的值。
解决
对于裴蜀定理 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b),我们可以把这个式子转化一下。
推式子
通过辗转相除可得
a x + b y = gcd ( b , a m o d b ) ax+by=\gcd(b,a\mod b) ax+by=gcd(b,amodb)
通过裴蜀定理反向可得
a x + b y = gcd ( b , a m o d b ) = b x ′ + ( a m o d b ) y ′ ax+by=\gcd(b,a \mod b)=bx'+(a \mod b)y' ax+by=gcd(b,amodb)=bx′+(amodb)y′
把 GCD 去掉可得
a x + b y = b x ′ + ( a m o d b ) y ′ ax+by=bx'+(a \mod b)y' ax+by=bx′+(amodb)y′
根据模的意义可得
a x + b y = b x ′ + ( a − ⌊ a b ⌋ ⋅ b ) y ′ ax+by=bx'+(a-\lfloor \frac{a}{b}\rfloor \cdot b)y' ax+by=bx′+(a−⌊ba⌋⋅b)y′
拆括号可得
a x + b y = b x ′ + a y ′ − ⌊ a b ⌋ ⋅ b y ′ ax+by=bx'+ay'- \lfloor \frac{a}{b}\rfloor \cdot by' ax+by=bx′+ay′−⌊ba⌋⋅by′
合并同类项可得
a x + b y = a y ′ + b ( x ′ − ⌊ a b ⌋ ⋅ y ′ ) ax+by=ay'+ b(x'-\lfloor \frac{a}{b} \rfloor \cdot y') ax+by=ay′+b(x′−⌊ba⌋⋅y′)
发现相似项,移项可得
x = y ′ , y = x ′ − ⌊ a b ⌋ ⋅ y ′ x=y',y=x'-\lfloor \frac{a}{b} \rfloor \cdot y' x=y′,y=x′−⌊ba⌋⋅y′。
意义
思考一下 x ′ , y ′ x',y' x′,y′ 的意义,结合一下欧几里得定理。
我们发现 x ′ , y ′ x',y' x′,y′ 实际上就是下一次(后面要考),进行欧几里得算法是 x , y x,y x,y 的值。
那么我们只需要进行迭代 x , y x,y x,y 就行了,迭代的操作是推出来的式子吧 ′ ' ′ 去掉。
实现
用欧几里得算法的框架进行迭代,每次的 x , y x,y x,y 迭代改变即可。
注意:新的 x , y x,y x,y 是下一次欧几里得算法 x , y x,y x,y 的值,而并非上一次,所以我们应该把代码放到递归中的归部分的代码。
初值
但是写完代码的我发现了没有初值。
在欧几里得算法中,对于跳出递归的步骤是需要满足 b = 0 b=0 b=0 的,所以问题中的多项式就会变成这样:
gcd ( a , b ) = a x + 0 y \gcd(a,b)=ax+0y gcd(a,b)=ax+0y
那么 a a a 是已知的, x x x 就一定是 1 1 1, y y y 就一定是 0 0 0 。
CODE
#include<bits/stdc++.h>
#define int long long
using namespace std;
int a,b;
int x,y;
int exgcd(int a,int b)
{
if(b==0)
{
x=1,y=0;
return a;
}
int ans=exgcd(b,a%b);
int temp=x;
x=y;
y=temp-(a/b)*y;
return ans;
}
main()
{
cin>>a>>b;
cout<<exgcd(a,b)<<" "<<x<<" "<<y<<"\n";
return 0;
}