中国剩余定理及扩展

挂链接

中国剩余定理

m1,m2,...,mk m 1 , m 2 , . . . , m k 两两互质
则对于方程组
xa1(mod m1) x ≡ a 1 ( m o d   m 1 )
xa2(mod m2) x ≡ a 2 ( m o d   m 2 )
... . . .
xak(mod mk) x ≡ a k ( m o d   m k )
有整数解
并且在模 M=Πmi M = Π m i 的意义下解唯一
(aiM/mi)(mod M) ∑ ( a i ∗ M / m i ) ( m o d   M )

Exgcd E x g c d 一波求解就好了

证明:
对于方程组
x0(mod m1) x ≡ 0 ( m o d   m 1 )
x0(mod m2) x ≡ 0 ( m o d   m 2 )
... . . .
x1(mod mi) x ≡ 1 ( m o d   m i )
... . . .
x0(mod mk) x ≡ 0 ( m o d   m k )
就等价于求解
(M/mi)x1(mod mi) ( M / m i ) x ≡ 1 ( m o d   m i )

而如果 xc(mod mi) x ≡ c ( m o d   m i )
那么 axac(mod mi) a ∗ x ≡ a ∗ c ( m o d   m i )

扩展

求解模数不互质情况下的线性方程组

考虑合并两个方程组
xai(mod mi) x ≡ a i ( m o d   m i )
xai+1(mod mi+1) x ≡ a i + 1 ( m o d   m i + 1 )

写成
x=ai+x1mi=ai+1+x2mi+1 x = a i + x 1 ∗ m i = a i + 1 + x 2 ∗ m i + 1
的形式
x x 最小,那么可以先解出x1最小的解 x x ′ ,带入就是
直接 Exgcd E x g c d 求解 x1mi+x2mi+1=ai+1ai x 1 ∗ m i + x 2 ∗ m i + 1 = a i + 1 − a i ,就好了

合并之后
显然新的方程就是
xx(mod lcm(mi,mi+1)) x ≡ x ′ ( m o d   l c m ( m i , m i + 1 ) )

就可以了

代码

POJ2891

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;

template <class Int>
IL void Input(RG Int &x){
    RG int z = 1; RG char c = getchar(); x = 0;
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    x *= z;
}

IL ll ExGcd(RG ll a, RG ll b, RG ll &x, RG ll &y){
    if(!b){
        x = 1, y = 0;
        return a;
    }
    RG ll d = ExGcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

const int maxn(1e5 + 5);

int n, flg;
ll ans, x, y, m[maxn], b[maxn];

int main(RG int argc, RG char* argv[]){
    while(scanf("%d", &n) != EOF){
        ans = flg = 0;
        for(RG int i = 1; i <= n; ++i) Input(m[i]), Input(b[i]);
        for(RG int i = 2; i <= n; ++i){
            RG ll d = ExGcd(m[1], m[i], x, y), g = b[i] - b[1], t;
            if(g % d){
                flg = 1;
                break;
            }
            x *= g / d, t = m[i] / d, x = (x % t + t) % t;
            b[1] += m[1] * x, m[1] *= t, b[1] %= m[1];
        }
        if(flg) puts("-1");
        else printf("%lld\n", (b[1] % m[1] + m[1]) % m[1]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值