歐幾里得:
首先要明確歐幾里得算法,就是我們所說的輾轉相除法。
就是求兩個數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
我們再考慮一個問題:
怎麼由一組通解得到多個解?
那肯定是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;
}
歡迎指正