1. 程式人生 > 實用技巧 >數論複習_歐幾里得演算法與擴充套件歐幾里得演算法

數論複習_歐幾里得演算法與擴充套件歐幾里得演算法

在小學二年級,我們學過歐幾里得演算法,又叫輾轉相除法。

其程式碼描述為:

ll gcd(ll a, ll b) {
	return b == 0 ? a : gcd(b, a % b);
}

當然對於我們這種學過STL的何必寫上面的傻逼程式碼

直接呼叫__gcd(a, b)這個函式即可求解兩個數的最大公因數。

歐幾里得演算法告訴我們一件事情:

兩個數的最大公因數等於較小的那個數和他們兩個餘數的最大公因數

證明過程

然而事實上我們需要會用這個結論即可

同時最小公倍數等於a*b/gcd(a, b)

然而這些並不是重點~

重點是擴充套件歐幾里得演算法

首先,擴充套件歐幾里得演算法需要解決的問題是

已知方程:ax+by=gcd(a, b)(這個等式又叫做貝祖等式)

由幾千年前一個大佬的結論可以知道在a, 一定存在整數x, y使得上述結論成立

如何求解這個x, y就需要用到擴充套件歐幾里得演算法

程式碼實現:

void exgcd(ll a, ll b, ll &x, ll &y) {
	if(b == 0) {
		x = 1;
		y = 0;
		return;
	}
	else {
		exgcd(b, a % b, x, y);
		ll temp = x;
		x = y;
		y = temp - a / b * y;
	}
}

在實際應用之中不會存在這麼直接的問題,利用擴充套件歐幾里得演算法,我們可以求解乘法逆元

介紹一些雜七雜八的定理:

乘法逆元:

如果ax≡1 (mod p),且gcd(a,p)=1(a與p互質),則稱a關於模p的乘法逆元為x。下文中,x都表示乘法逆元。

費馬小定理:

求乘法逆元的方法:寫成ax + py = 1的形式求出來的x就是a的逆元

a/b=a/b*(b * b ^ (M-2))=a*(b ^ (M-2)) (mod M)

來幾道例題

題目一

擴充套件歐幾里得演算法裸題

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {
	return b == 0 ? a : gcd(b, a % b);
}
void exgcd(ll a, ll b, ll &x, ll &y) {
	if(b == 0) {
		x = 1;
		y = 0;
		return;
	}
	else {
		exgcd(b, a % b, x, y);
		ll temp = x;
		x = y;
		y = temp - a / b * y;
	}
}
int main () {
	ll A, B;
	ll x, y;
	while(cin >> A >> B) {
		exgcd(A, B, x, y);
		cout << x << " " << y << " " << gcd(A, B) << endl;
	}
}
/*
4 6
17 17
*/

題目二

非常經典的題目

列出方程得到相應的方程,變形轉化為擴充套件歐幾里得演算法求解的方程如果不能求解,說明不能碰面

#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {
	return b == 0 ? a : gcd(b, a % b);
}
void exgcd(ll a, ll b, ll &x, ll &y) {
	if(b == 0) {
		x = 1;
		y = 0;
		return;
	}
	else {
		exgcd(b, a % b, x, y);
		ll temp = x;
		x = y;
		y = temp - a / b * y;
	}
}
int main () {
	ll x, y, m, n, l;
	cin >> x >> y >> m >> n >> l;
	ll t, k;
	if((x - y) % gcd(n - m, l)) {
		cout << "Impossible" << endl;
	}
	else {
		exgcd(n - m, l, t, k);	
		t = t * (x - y) / gcd(n - m, l);
		t = (t % l + l) % l;
		cout << t << endl;
	}
	
	
}

題目三

與上題有相似之處,列出擴充套件歐幾里得方程,運用板子求解。當然該題也可以用費馬小定理轉化為冪的形式,然後用快速冪求解。

#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {
	return b == 0 ? a : gcd(b, a % b);
}
void exgcd(ll a, ll b, ll &x, ll &y) {
	if(b == 0) {
		x = 1;
		y = 0;
		return;
	}
	else {
		exgcd(b, a % b, x, y);
		ll temp = x;
		x = y;
		y = temp - a / b * y;
	}
}
int main () {
	int T;
	cin >> T;
	while(T--) {
		ll n, B;
		cin >> n >> B;
		ll ans, sb;
		exgcd(B, 9973, ans, sb);
		ans *= n;
		ans = (ans % 9973 + 9973) % 9973;
		cout << ans << endl;
	}
}

綜上是一些數論的最基礎的知識複習,看了部落格有問題可以私聊或者留言,以後會繼續更新相關的數論知識~

更新於:2020-10-07  20:08:39