扩展欧几里得算法
介绍扩展欧几里得算法之前,我们先介绍贝祖定理,即对任意整数a,b,那么一定存在整数x,y,使得\(ax+by=gcd(a,b)\)
使用欧几里得算法(辗转相除法)我们可知:当到达递归边界时有\(b=0,a=gcd(a,b)\),我们可以得到一个式子\(a·1+b·0=gcd(a,b),x=1,y=0\),注意这时的\(a\)和\(b\)与最开始的\(a\)和\(b\)不一样, 所以我们要想求解出最开始的\(x\)和\(y\),就要回到最开始的样式,因为我们这个过程是使用递归算法得到的,所以我们这需要逆向递推,就可以算出最开始的\(x\)和\(y\)。
上下两层\(x\)和\(y\)的关系如下:
因为\(ax+by=gcd(a,b)\) ,\(bx+(a\)%\(b)y=gcd(b,a\)%\(b)\);
又因为\(gcd(a,b)=gcd(b,a\)%\(b)\);
所以\(ax_{0}+by_{0}=bx+(a\)%\(b)y=bx+[a-(a/b)b]y\);
即\(ax_{0}+by_{0}=ay+b[x-(a/b)y]\);
所以\(x_{0}=y\) \(y_{0}=x-(a/b)y\);
typedef long long ll;
ll x, y;
void exgcd(ll a, ll b){//扩展欧几里得算法
if(b == 0){
x = 1;
y = 0;
return;
}
exgcd(b,a%b);
ll temp = x;//向上推求解最开始的x,y
x = y;
y = temp - (a/b) * y;
}
求解任意方程\(ax+by=n\)的一个整数解
在上面我们证明\(ax+by=gcd(a,b)\)一定有整数解,进一步利用它来求解任意方程\(ax+by=n\),证明如下:
- 判断方程\(ax+by=n\)是否有整数解,有解的条件是\(gcd(a,b)|n\)(\(gcd(a,b)\)可以整除n);
- 用扩展欧几里得算法求\(ax+by=gcd(a,b)\)的一个解\((x_{0},y_{0})\);
- 在\(ax_{0}+by_{0}=gcd(a,b)\)的两边同时乘以\(n/gcd(a,b)\),即 \(ax_{0}n/gcd(a,b)+by_{0}n/gcd(a,b)=n\);
- 对照\(ax+by=n\),可得它的一个整数解\((x_{1},y_{1})\);
\(x_{1}=x_{0}n/gcd(a,b)\) \(y_{1}=y_{0}n/gcd(a,b)\)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll x, y;
ll exgcd(ll a, ll b){
if(b == 0){
x = 1;
y = 0;
return a;
}
ll ans = exgcd(b,a%b);
ll temp = x;
x = y;
y = temp - (a/b) * y;
return ans;
}
int main(){
ll a, b, n;
cin >> a >> b >> n;
ll ans = exgcd(a,b);
if(n % ans == 0) cout << n/ans*x << " " << n/ans*y << endl;
//cout << (x*n/ans%(b/ans)+b/ans)%(b/ans) << endl; x的非负数处理
return 0;
}