1. 程式人生 > >[數論][exgcd]同余方程

[數論][exgcd]同余方程

參數 pos esp 包含 變量 gcd 回溯 pan div

題目描述

求關於 x 的同余方程 ax ≡ 1 (mod b)的最小正整數解。

輸入

輸入只有一行,包含兩個正整數 a, b,用一個空格隔開。

輸出

輸出只有一行,包含一個正整數 x0,即最小正整數解。輸入數據保證一定有解。

樣例輸入

3 10

樣例輸出

7

提示

對於 100%的數據,2 ≤a, b≤ 2,000,000,000。

思路:exgcd的應用——求解不定方程、求解線性同余方程

-----------------------------------------------------------------------------

下面給出關於ecgcd的詳解與模板:(以下討論的數全為整數)

問題1:給出方程 ax+by=gcd(a,b) ,求解滿足方程的x,y的一組解(求解不定方程)

解: 構造一個相同形式的方程——bx1+(a%b)y1=gcd(b,a%b)

聯立上述兩個方程:因為由歐幾裏得定理有gcd(a,b)=gcd(b,a%b),所以ax+by=bx1+(a%b)y1

因為a%b=a-a/b*b,帶入上式並整理得ax+by=ay1+b(x1-a/b*y1)

對比等式左右兩邊得x=y1 , y=x1-a/b*y1

因此,若知道滿足方程bx1+(a%b)y1=gcd(b,a%b)的x1,y1的一組解,就可以得出x,y的一組解

同理關於方程bx1+(a%b)y1=gcd(b,a%b)的求解也可以用同樣的方法由相應的x2,y2得出

如此遞歸下去,當遞歸到最底層b=0時,顯然方程的一組解為x=1,y=0

得到這組解後,便可以回溯得到最頂層方程即ax+by=gcd(a,b)的一組解了。

引理:存在 x , y 使得 ax+by=gcd(a,b)

上述解法,我們可以用遞歸的方法來實現。

void exgcd(ll a,ll b){//x,y為兩參數,a,b為兩參數的系數
  if(b==0) y=(x=1)-1;//x,y為全局變量
  else{
    exgcd(b,a
%b); ll tmp=x; x=y; y=tmp-a/b*y; } }

上述代碼實現了求方程ax+by=gcd(a,b)的一組解x和y,可以由這一組解得到方程的其他多組解:(設x0,y0為一組已知解,x,y為通解)

x=x0+b/gcd(a,b)*k

y=y0+a/gcd(a,b)*k (其中k為整數)

將通解帶入原方程即可驗證。

問題2:給出方程 ax+by=r,求解滿足方程的x,y的一組解(求解不定方程)

解: 當r%gcd(a,b)!=0時,方程無整數解

當r%gcd(a,b)==0時,先利用exgcd求出方程ax+by=gcd(a,b)的一組解x0,y0,則有ax+by=r的一組解為x1=x0*r/c,y1=y0*r/c

原方程的通解為 x=x1+b/gcd(a,b)*k

y=y1+a/gcd(a,b)*k

問題3:求關於 模方程 ax%b=c(ax=c(mod b))的解x(求解線性同余方程)

解:方程轉換為 ax+by=c ,即利用exgcd求不定方程的解x,y(最後只需要x的值)

原方程的通解為x=x0+b/gcd(a,b)*k(其中x0為ax%b=c的其中一解)

設s=b/gcd(a,b),則 x 的最小正整數解為 (x1%s+s)%s

-----------------------------------------------------------------------------

AC代碼:

#include <iostream>
#include<cstdio>
#define ll long long
using namespace std;

ll x,y;

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

int main()
{
    ll a,b;
    scanf("%lld%lld",&a,&b);
    exgcd(a,b);
    while(x<=0) x+=b;
    printf("%lld\n",x);
    return 0;
}

[數論][exgcd]同余方程