扩展欧几里得算法

介绍扩展欧几里得算法之前,我们先介绍贝祖定理,即对任意整数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\),证明如下:

  1. 判断方程\(ax+by=n\)是否有整数解,有解的条件是\(gcd(a,b)|n\)\(gcd(a,b)\)可以整除n);
  2. 用扩展欧几里得算法求\(ax+by=gcd(a,b)\)的一个解\((x_{0},y_{0})\);
  3. \(ax_{0}+by_{0}=gcd(a,b)\)的两边同时乘以\(n/gcd(a,b)\),即 \(ax_{0}n/gcd(a,b)+by_{0}n/gcd(a,b)=n\);
  4. 对照\(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;
}
posted @ 2021-01-25 19:13  h星宇  阅读(172)  评论(0编辑  收藏  举报