模线性方程组、中国剩余定理

对模线性方程 ax = b (mod m),有 ax = k*m + b,其中 k 是整数。
移项后有 ax - km = b,转化到了 EXGCD 的解法。


若有模线性方程组如下:
x=b1(modm1) x = b 1 ( m o d m 1 )
x=b2(modm2) x = b 2 ( m o d m 2 )
x=b3(modm3) x = b 3 ( m o d m 3 )
…………
x=bk(modmk) x = b k ( m o d m k )
需要我们解出一个 x x


方法一:

我们取前两个式子,则有
x=k1m1+a1 x = k 1 ∗ m 1 + a 1
x=k2m2+a2 x = k 2 ∗ m 2 + a 2
相应变动后有
m1k1m2k2=a2a1 m 1 ∗ k 1 − m 2 ∗ k 2 = a 2 − a 1
其中 m1m2a2a1 m 1 , m 2 , a 2 , a 1 是已知的,由 exgcd 能够得到一组特解 k1k2 k 1 , k 2 .
k1 k 1 带回第一个式子能得到一个特解 X。
那么其他的解 x=X+klcm(m1,m2) x = X + k ∗ l c m ( m 1 , m 2 ) ,k是自然数。
变形后可以得到
x=X(modlcm(m1,m2)) x = X ( m o d l c m ( m 1 , m 2 ) )
再和 x=b3(modm3) x = b 3 ( m o d m 3 ) 继续上述过程,可以得到所有方程的解。


方法二:

中国剩余定理:

有一次同余方程组如下:
x=b1(modm1) x = b 1 ( m o d m 1 )
x=b2(modm2) x = b 2 ( m o d m 2 )
x=b3(modm3) x = b 3 ( m o d m 3 )
….
x=bk(modmk) x = b k ( m o d m k )

m1,m2,m3...mk m 1 , m 2 , m 3 . . . m k 两两互素的正整数,对于任意的 b1,b2,b3...bk b 1 , b 2 , b 3 . . . b k ,一次同余方程组必定有解,且只有一组解。

M=m1m2m3...mk M = m 1 ∗ m 2 ∗ m 3 ∗ . . . ∗ m k Mi=Mmi M i = M m i
Mi1 M i − 1 满足 Mi1Mi=1(mod(mi)) M i − 1 ∗ M i = 1 ( m o d ( m i ) )
则同余方程组的解为 x=(MiMi1bi)(modM) x = ( ∑ M i ∗ M i − 1 ∗ b i ) ( m o d M )


方法一代码:

#include 
#include 
#include 
#define ll long long
using namespace std;

ll mr[105];
ll ar[105];

ll 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);
    ll t = x;
    x = y;
    y = t - a/b*y;
    return r;
}

ll solve (int n) {
    ll M = mr[1], A = ar[1], x, y;
    for (int i = 2; i <= n; i++) {
        ll d = exgcd(M, mr[i], x, y);
        if (abs(A - ar[i]) % d != 0) {
            return -1;
        }
        x = (A - ar[i]) / d * x;
        ll tmp = ar[i] / d;
        x = x % tmp;
        A = x*M + A;
        M = M*ar[i]/d;
        A = A % M;
        if (A < 0) {
            A += M;
        }
    }
    if (A == 0) {
        return M;
    }
    else {
        return (A%M+M)%M;
    }
}

方法二代码:

#include 
#include 
#include 
#define ll long long
using namespace std;

ll mr[105];     //模
ll ar[105];     //余数

ll 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);
    ll t = x;
    x = y;
    y = t - a/b*y;
    return r;
}

ll solve (int n) {
    ll ans = 0, M = 1;
    for (int i = 1; i < n; i++) {
        M *= ar[i];
    }
    for (int i = 1; i <= n; i++) {
        ll tmp = M / mr[i];
        ll x, y;
        exgcd(tmp, mr[i], x, y);
        ans = (ans + tmp*x*ar[i]) % M;
    }
    return (ans%M+M)%M;
}

你可能感兴趣的:(数论)