同餘與同餘方程(擴充套件歐幾里得)
同餘應該是數論中比較基礎的一個東西了。感覺挺重要的。。。高中沒學好到大學來補了。
涉及3個數,a,b,m。就是a % m == b % m.
可以寫成:a b(mod m)。
一、同餘及其一些性質
同餘有一些顯然性質,有的時候會有很大功效。(不列舉了,一般書上都有的)。
例1:給定整數n,m,k.求n^m mod k的值。m,n,k*k為長整型範圍內的自然數。
這樣的題根據資料型別有不同的解法:
這裡m還在資料型別可表示的範圍內,當m極大時,就要用到尤拉降冪這個東西。
這裡說一下m還在資料型別可儲存範圍內的做法。
n^1 n (mod k)
n^2 (n mod 7) * (n mod 7) mod 7
n^4 (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 c(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;