淺談拓展歐幾里得算法、最小正整數解與乘法逆元

歐幾里得:

首先要明確歐幾里得算法,就是我們所說的輾轉相除法。
就是求兩個數a,b的最大公因數gcd(a,b)

ll gcd(ll a,ll b)    //歐幾里得算法 
{                    //輾轉相除法 
	if(a%b==0) return b;
	return gcd(b,a%b);
}

拓展歐幾里得算法

通俗來說就是求二元一次方程 Ax+By=gcd(A,B) 的(x,y)的所有的解。(假設A,B已知)
我們的方法是通過這組方程的一個特解,得出他的通解。
那麼就有兩個問題
1.如何得到他的特解?
2.如何得由特解得到通解?****

1.找特解

由歐幾里得算法可以將gcd(A,B)寫成gcd(B,A%B)。
得到一個新的方程

Bx2+(A%B) * y2=gcd(B,A%B); -------------1

A%B=A-(A/B)*B;
再次改寫方程

Bx2+[A-(A/B) * B ] y2=gcd(B,A%B);*------------2

當gcd(B,A%B)一直向下寫,直到A%B=0 時;
由1號方程得
Bx2=B;
這時候我們得出方程的一組特解爲x2=1,y2=0;
此時我們已經解決了第一個問題找到方程組的特解。

2.如何由特解得出通解
繼續觀察式子 2 。我們既然已經得出特解x2與y2。那麼我們要是知道x2與x的關係,y2與y的關係,我們就能得出通解(x,y)。

現在對 2 式進行整理得到:

Ay2+B * [x2-(A/B)*y2]=gcd

原式爲 Ax+By=gcd
此時我們可以得到通解與特解的關係

x=y2;
y=x2-(A/B)*y2

因爲我們求特解的過程是一步一步遞推下去的,所以我們求通解的過程就是一個回溯的過程。
我們拿一個3x+5y=1的例子來說


這裏(2,-1)就是方程3x+5y=1的一組解
**總結:求通解的過程中主要還是運用我們上面得出的通解與特解的關係,因爲每一步A,B係數是不同的所以要一步一步的由特解回溯到通解

拓展歐幾里得
#include
#include
#include
#include
using namespace std;
const int N=1e6+10;
typedef long long ll;
typedef unsigned long long ull;
ll exgcd(ll a,ll b,ll &x,ll &y) {
if(b==0) {
x=1;
y=0;
return a;
}
ll res= exgcd(b,a%b,x,y);
ll t;
t=x;
x=y;
y=t-a/b*y;
return res;
}
int main() {
ll a,b,x,y;
cin>>a>>b;
ll anss = exgcd(a,b,x,y);
cout<<anss<<" “<<x<<” "<<y;
return 0;
}

我們再考慮一個問題:
怎麼由一組通解得到多個解?

那肯定是x,y的值一增一減才能保證等式
ax+by=gcd的成立
我們知道a,b最小公倍數的等於(a*b)/gcd(a,b)
那麼當x=x+b/gcd(a,b),y=y-a/gcd(a,b)的時候代入原式
得到 a *(x+b/gcd(a,b)) + b *( y-a/gcd(a,b))
不難看出每次讓x或者y的值增減一個a,b的最小公倍數後,原式的值是保持不變的。
那麼我們可以得到x或者y的變化最小週期就爲b/gcd(a,b)或者a/gcd(a,b)
另外,也不難得出如果Ax+By=C,如果C%gcd(A,B)!=0,那麼方程組一定無解

由此我們引出最小正整數解
**

最小正整數解

**
拓展歐幾里得主要應用於求解方程的解
ax≡b(mod)l
ax-ly=b;
由上面拓展歐幾里得算法我們可以求出x,但是x可能爲負數,或者x並不是一個最小的正整數解
我們得到了x的週期,在該式子中週期T=l/gcd(a,l);
我們可以選擇這樣一種處理方式
x=((x%T)+T)%T;
保證x爲最小正整數解

乘法逆元

在一個模系p中只有包含[1,p-1]的所有整數,所以在模系p中計算除法的時候由於無法整除出現精度問題,所以我們引入乘法逆元
ax≡1(mod)p
這時x爲在模系p中a的逆元
學習完拓展歐幾里得後
轉化一下
ax-pk=1
a的逆元x的存在條件爲gcd(a,p)=1
同樣用拓展歐幾里得的代碼可以求出a的逆元x;

**拓展歐幾里得,乘法逆元,最小整數解**
#include <iostream>
#include <cstring>
#include <algorithm>
#include<map>
using namespace std;
const int N=1e6+10;
typedef long long ll;
typedef unsigned long long ull;
l 
ll exgcd(ll a,ll b,ll &x,ll &y) {
	if(b==0) {
		x=1;
		y=0;
		return a;
	}
	ll res=	exgcd(b,a%b,x,y);
	ll t;
	t=x;
	x=y;
	y=t-a/b*y;
	return res;
}
int main() {
	// ax-pk=1
	//p =1000000007
	ll a,b,x,y;
	cin>>a>>b;
	exgcd(a,b,x,y);
	ll ans=exgcd(a,b,x,y);
// ax+by=c
x=x*c/gcd(a,b);
	ll t=b/ans;
	x=(x%t+t)%t;
	cout<<x;
	return 0;
}

歡迎指正

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章