欧几里得与扩展中国剩余定理ExCrt

欧几里得算法

为什么要放欧几里得算法,因为这个玩意是扩展欧几里得的铺垫,为什么要将扩展欧几里得,因为这个玩意是中国剩余定理的铺垫。
很简单,就是要我们求。由于证明过程十分繁琐并且没有什么很大的意义,所以便不多管闲事地证明了,结论也很简单:。于是可以不断递归,直到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 ;
}
全部评论

相关推荐

头像
05-12 09:14
点赞 评论 收藏
转发
2 2 评论
分享
牛客网
牛客企业服务