欧几里得算法与 EX
欧几里得算法
欧几里得算法又称辗转相除法,用来求两个数的最大公约数的算法。
省流:\(gcd(a,b)=gcd(b,a\mod b)\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int a,b;
int gcd(int x,int y){
return y==0?x:gcd(y,x%y);
}
int main(){
cin>>a>>b;
cout<<gcd(a,b);
return 0;
}
拓展欧几里得算法 exgcd
常用于求解 \(ax+by=gcd(a,b)\) 的一组可行解。
接下来就是推例子了:
\[\because gcd(a,b)=gcd(b,a\mod b)
\]
\[\therefore ax+by=bx_2+(a \mod b)y_2
\]
\[\because a \mod b=a-b\times \lfloor \frac{a}{b} \rfloor
\]
\[\therefore ax+by=bx_2+( a-b\times \lfloor \frac{a}{b} \rfloor )y_2
\]
\[\therefore ax+by=bx_2+ay_2-by_2\lfloor \frac{a}{b} \rfloor
\]
\[\therefore ax+by=ay_2+b(x_2-y_2\lfloor \frac{a}{b} \rfloor)
\]
然后我们就发现 \(x=y_2,y=x_2-y_2\lfloor \frac{a}{b} \rfloor\)
\(x_2,y_2\) 又可以从 \(x_3,y_3\) 推过来。
我们就需要不断做欧几里得法,当 \(a=gcd(a,b),b=0\) 时,我们这时取 \(x_n=1,y_n=0\),因为 \(b=0\) 所以 \(y_n\) 取任何数都没问题,但取 \(0\) 的时候 \(x\) 和 \(y\) 增长速度更慢一些,还有注意解可能为负数的情况,所以要取模变正数。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
void exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x=1,y=0;
return;
}
exgcd(b,a%b,y,x);
y-=a/b*x;
}
int main(){
ios::sync_with_stdio(false);
ll a,b;
cin>>a>>b;
ll d=__gcd(a,b);
if(b%d!=0){
cout<<"impossible\n";
}
else{
ll x,y;
exgcd(a,b,x,y);
x=(x*(b/d)%b+b)%b;//注意这要调整解
cout<<x<<"\n";
}
return 0;
}