欧几里得算法
为什么要放欧几里得算法,因为这个玩意是扩展欧几里得的铺垫,为什么要将扩展欧几里得,因为这个玩意是中国剩余定理的铺垫。
很简单,就是要我们求。由于证明过程十分繁琐并且没有什么很大的意义,所以便不多管闲事地证明了,结论也很简单:
。于是可以不断递归,直到j变成0,然后返回i就可以了,很常见的方法,直接放代码了。
inline int Gcd(int X, int Y) {
if (Y == 0) return X ;
return Gcd(Y, X % Y) ;
} 裴蜀定理
裴蜀定理是扩展欧几里得算法的第二个铺垫,也是一个关于最大公约数的定理。
假设有一个线性方程,问这个方程有没有整数解,那么根据裴蜀定理我们就知道当
的时候线性方程才可能有整数解。简单的证明就是
显然
。对于
的情况有没有整数解我们便需要用到扩展欧几里得。
扩展欧几里得
对于
当的时候,式子就可以变成
可以知道这个式子必然是有整数解的。我们可以对于进行欧几里得算法,得到最大公约数,然后保存辗转相除法中的式子倒推便可以得到
的整数解。那么也就是证明了裴蜀定理,同时也给出了计算线性方程的整数解的方法。
inline int Exgcd(int a, int b, int & X, int & Y) {
if (b == 0) {X = 1, Y = 0 ; return a ;}
int R = Exgcd(b, a % b, X, Y) ;
int E = X ; X = Y ; Y = E - a / b * Y ;
return R ;
} 中国剩余定理
此算法称为扩展中国剩余定理,而中国剩余定理满足之间两两互质,我们先从中国剩余定理说起。
还是使用上面的式子,假设方程组有解。那么我们设,(当然也可以设
,效果是一样的)且有n个
,也就是除了第i个以外其他n-1个
的乘积。以及
,则我们知道
于是有结论:方程组的通解形式为
以上是通解形式,而通解有无数个,对于每一个解加上依然是方程组的解,其中
。
证明
关于证明,因为我们知道
所以有
而因为所有的之间两两互质,因此对于除了
之外的所有的
都有
因此
满足
因此,,所以
就是方程的一个特殊解。而至于为什么加上若干个
都是解我想就不用我再证明了吧。
long long a[MAXN], m[MAXN], n ;
inline long long Crt() {
long long M = 1 ;
for (int i = 1 ; i <= n ; i ++) M *= m[i] ;
long long X = 0 ;
for (int i = 1 ; i <= N ; i ++) {
long long x, y ;
long long M_i = M / m[i] ;
Exgcd(M_i, m[i], x, y) ;
X = (X + M_i * x * a[i]) % M ;
} return (X + M) % M ;
} 扩展中国剩余定理
然后关于扩展中国剩余定理,相较之就是取消掉了两两互质这个条件。
我们依然假设,那么假设我们已经知道了前
个式子的方程通解为
,那么在加入第i个方程后的通解,只消求出一个满足
的
就可以。
直接欧几里得求解即可。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std ;
typedef long long LL ;
const int MAXN = 100010 ;
const int MAXM = 100010 ;
int N ;
long long A[MAXN], B[MAXN] ;
inline long long Read() {
long long X = 0, F = 1 ; char ch = getchar() ;
while (ch > '9' || ch < '0') F = (ch == '-' ? - 1 : 1), ch = getchar() ;
while (ch >= '0' && ch <= '9') X=(X<<1)+(X<<3)+(ch^48), ch = getchar() ;
return X * F ;
}
inline long long Exgcd(LL a, LL b, LL & X, LL & Y) {
if (b == 0) {
X = 1 ; Y = 0 ;
return a ;
}
LL R = Exgcd(b, a % b, X, Y), E = X ;
X = Y ; Y = E - a / b * Y ;return R ;
}
inline long long Quick_Mul(LL X, LL Y, LL Mod) {
long long Ans = 0 ; while (Y) {
if (Y & 1) Ans = (Ans + X) % Mod ;
X = (X + X) % Mod ; Y >>= 1 ;
} return Ans ;
}
inline long long Excrt() {
long long X, Y, M = B[1], Ans = A[1] ;
for (int i = 2 ; i <= N ; i ++) {
LL a = M, b = B[i], C = (A[i] - Ans % b + b) % b ;
LL R = Exgcd(a, b, X, Y), E = b / R ;
if (C % R != 0) return - 1 ;
X = Quick_Mul(X, C / R, E) ; Ans += X * M ;
M = M * E ; Ans = (Ans % M + M) % M ;
} return (Ans % M + M) % M ;
}
int main() {
N = Read() ;
for (int i = 1 ; i <= N ; i ++)
B[i] = Read(), A[i] = Read() ;
printf("%lld", Excrt()) ;
return 0 ;
} 
京公网安备 11010502036488号