1. 程式人生 > >同餘與同餘方程(擴充套件歐幾里得)

同餘與同餘方程(擴充套件歐幾里得)

同餘應該是數論中比較基礎的一個東西了。感覺挺重要的。。。高中沒學好到大學來補了。

涉及3個數,a,b,m。就是a % m == b % m.

可以寫成:a \equiv b(mod m)。

一、同餘及其一些性質

同餘有一些顯然性質,有的時候會有很大功效。(不列舉了,一般書上都有的)。

例1:給定整數n,m,k.求n^m mod k的值。m,n,k*k為長整型範圍內的自然數。

這樣的題根據資料型別有不同的解法:

這裡m還在資料型別可表示的範圍內,當m極大時,就要用到尤拉降冪這個東西。

這裡說一下m還在資料型別可儲存範圍內的做法。

n^1  \equiv n (mod k)

n^2  \equiv (n mod 7) * (n mod 7) mod 7

n^4  \equiv (n^2 mod 7) * (n^2 mod 7) mod 7

......

將m進行二進位制分解,然後遞推得到結果,當然遞迴也是可以的。

二、同餘方程

GCD:最大公約數  輾轉相除法 一句話: 

int GCD(int x, int y){
    return y == 0 ? x : GCD(y, x % y);
}

LCM:   最小公倍數

int LCM(int x, int y){
    return x * y / GCD(x, y);
}

擴充套件歐幾里得演算法:

   這個演算法是用來求已知a,b時,求一組p,q使得p*a+q*b=GCD(a,b)。由某些定理,解一定存在。

  因為GCD(a,b) = GCD(b, a%b)。

 p*a + q*b = GCD(a,b) = GCD(b, a % b)

  即:p*a + q*b = p * b + q * (a % b) = p * b + q * (a - a / b * b) = q * a + (p - a/b * q) * b.

a,b都在不停的減小,最後b減小到0, 可以得出p=1,q=0。然後遞歸回去,得到最終的p,q。

同餘方程:

    求一組x,y使得a*x+b*y=c。首先該方程等價於a*x \equivc(mod b),有整數解的充分必要條件是c % GCD(a,b)=0。

int exgcd(int a, int b, int &x, int &y){
	if(b == 0){
		x = 1;
		y = 0;
		return a;
	}
	int k = exgcd(b, a % b, x, y);
	h = x;
	x = y;
	y = h - (a / b) * y;
	return k;
}

同餘方程:

   求關於x的同餘方程a * x = c(mod b)的解。

定理一:該同餘方程等價於a * x + b * y = c。有解的充分必要條件是c % GCD(a, b) = 0.我們可以先用擴充套件歐幾里得演算法得到

a * x + b * y = GCD(a, b)的一組解(x0,y0).然後兩邊同除GCD(a, b),同乘c,得到a * x0 * c / GCD(a, b) + b * y0 * c/GCD(a, b) = c

這樣就找到了方程的一組解(x0 * c / GCD(a, b), y0 * c / GCD(a, b))。

定理二:若GCD(a, b)=1,且x0,y0為a*x + b * y 的一組解,則該方程的任一解可表示為x = x0 + b * t, y = y0 - a * t,對任一整數t都成立。

往往我們要找x的最小整數解,那麼 t = b / GCD(a, b), x = (x % t + t) % t;此時x即為最小整數解。

bool TY(int a, int b, int c, int &x, int &y){
    int d = exgcd(a, b, x, y);
	if(c % d != 0) return 0;
	int k = c / d;
	x *= k;
	y *= k;
	return 1;
}//x是全域性變數,返回意義不大,為了方便處理無解的情況,把函式設為boo型別。

注意:求最小整數解時加上:

t = b / GCD(a, b),

x = (x % t + t) % t;