中国剩余定理以及扩展中国剩余定理

中国剩余定理

m 1 , m 2 , ⋯   , m n m1, m2,\cdots, m_n m1,m2,mn是两两互质的整数,对于下式的一元线性同余方程组有整数解
{ x ≡ a 1 (   m o d   m 1 ) x ≡ a 2 (   m o d   m 2 ) ⋮ x ≡ a n (   m o d   m n ) \begin{cases} x \equiv a_1(\bmod m_1) \\ x \equiv a_2(\bmod m_2) \\ \qquad \vdots \\ x \equiv a_n (\bmod m_n) \end{cases} xa1(modm1)xa2(modm2)xan(modmn)
解为:
x = ∑ i = 1 n a i ∗ M i ∗ M i − 1 x = \sum_{i=1}^{n}a_i * M_i * M_i^{-1} x=i=1naiMiMi1
其中: m = ∏ i = 1 n m i , M i = m m i m = \prod_{i=1}^{n}m_i,M_i = \frac{m}{m_i} m=i=1nmiMi=mim M i − 1 M_i^{-1} Mi1 M i M_i Mi的逆元,可以使用扩展欧几里得求解

具体证明可参考百度百科:中国剩余定理

代码模板:

LL CRT(LL a[], LL m[], int n)
{
    LL M = 1, ans = 0;
    for(int i = 1; i <= n; ++i) M *= m[i];
    for(int i = 1; i <= n; ++i)
    {
        LL x, y;
        LL Mi = M / m[i];
        exgcd(Mi, m[i], x, y);
        x = ((x % m[i]) + m[i] ) % m[i];
        ans = (ans  + a[i] * Mi * x ) ;
    }
    return ans;
}

扩展中国剩余定理

原题链接(模板题)
同样的,给出一个一元线性同余方程组:
{ x ≡ a 1 (   m o d   m 1 ) x ≡ a 2 (   m o d   m 2 ) ⋮ x ≡ a n (   m o d   m n ) \begin{cases} x \equiv a_1(\bmod m_1) \\ x \equiv a_2(\bmod m_2) \\ \qquad \vdots \\ x \equiv a_n (\bmod m_n) \end{cases} xa1(modm1)xa2(modm2)xan(modmn)
不保证 m 1 , m 2 , ⋯   , m n m_1, m_2, \cdots, m_n m1,m2,,mn两两互质。

先考虑前两个式子拿出来:

x = k 1 ∗ a 1 + m 1 ① x = k 2 ∗ a 2 + m 2 x = k_1 * a_1 + m_1① \\ x = k_2 * a_2 + m_2 x=k1a1+m1x=k2a2+m2
两式相减有:
k 1 ∗ a 1 + k 2 ∗ ( − a 2 ) = m 2 − m 1 ② k_1 * a_1 + k_2 * (-a_2) = m_2 - m_1 ② k1a1+k2(a2)=m2m1
这个式子两种情况:

  • d = g c d ( a 1 , − a 2 ) d = gcd(a_1, -a_2) d=gcd(a1,a2),如果 d ∤ ( m 2 − m 1 ) d∤(m_2 - m_1) d(m2m1),则无解
  • 否则可以用扩展欧几里得求出一组解 k 1 ′ {k_1}' k1 k 2 ′ {k_2}' k2,设 d = g c d ( a 1 , − a 2 ) , y = m 2 − m 1 d d = gcd(a_1, -a_2),y = \frac{m_2-m_1}{d} d=gcd(a1,a2),y=dm2m1
    我们将 k 1 ′ {k_1}' k1 k 2 ′ {k_2}' k2都扩大 y y y倍后,能满足 ② ②

接下来就是需要找到最小的解了。

我们有性质:
k 1 = k 1 + k ∗ a 2 d ③ k 2 = k 2 + k ∗ a 1 d k_1 = k_1 + k * \frac{a_2}{d} ③\\ \quad\\ k_2 = k_2 + k * \frac{a_1}{d} k1=k1+kda2k2=k2+kda1
其中: k ∈ Z k \in Z kZ,此时 k 1 , k 2 k_1, k_2 k1,k2仍然满足 ② ②
证明如下:
我们将新的 k 1 , k 2 k_1,k_2 k1,k2带入②式有:
( k 1 + k ∗ a 2 d ) ∗ a 1 + ( k 2 + k ∗ a 1 d ) ∗ ( − a 2 ) = k 1 ∗ a 1 + k ∗ a 1 ∗ a 2 d + k 2 ∗ ( − a 2 ) + k ∗ a 1 ∗ ( − a 2 ) d = k 1 ∗ a 1 + k 2 ∗ ( − a 2 ) (k_1 + k * \frac{a_2}{d})*a_1 + (k_2 + k * \frac{a_1}{d}) * (-a_2) \\ \quad \\=k_1*a_1+k*\frac{a_1*a_2}{d} +k_2*(-a_2) + k*\frac{a_1*(-a_2)}{d} \\ \quad \\ = k_1*a_1 + k_2*(-a_2) (k1+kda2)a1+(k2+kda1)(a2)=k1a1+kda1a2+k2(a2)+kda1(a2)=k1a1+k2(a2)
证毕
我们需要一个最小的非负这整数解,我们对 ③ ③ 式取模 a b s ( a 2 d ) abs(\frac{a_2}{d}) abs(da2)的到: k 1 = k 1   m o d   a b s ( a 2 d ) k_1 = k_1 \bmod abs(\frac{a_2}{d}) k1=k1modabs(da2)

  • 取绝对值,是为了因为不知道 a 2 d \frac{a_2}{d} da2的正负性,同时使得 k 1 k_1 k1尽可能的小

最后我们把得到的 k 1 k_1 k1带回①式有:
x = ( k 1 + k ∗ a 2 d ) ∗ a 1 + m 1 x = k 1 ∗ a 1 + m 1 + k ∗ a 1 ∗ a 2 d k i ∗ a i m i x = k ∗ a 1 ∗ a 2 d ⏞ + k 1 ∗ a 1 + m 1 ⏞ x = (k_1 + k * \frac{a_2}{d}) * a_1 + m_1 \\ \quad \\ x = k_1*a_1 + m_1 + k*\frac{a_1*a_2}{d} \\ k_i*a_i \quad \qquad \quad m_i \\ x = \overbrace{k *\frac{a_1*a_2}{d}} + \overbrace{k_1*a_1 + m_1} x=(k1+kda2)a1+m1x=k1a1+m1+kda1a2kiaimix=kda1a2 +k1a1+m1
这样:我们就把前两个式子合并为一个式子了,这样子取合并下面的式子。经过 n − 1 n-1 n1次合并,就将 n n n个式子合并为一个式子了。

扩展中国剩余定理模板:

LL exgcd(LL a, LL b, LL &x, LL &y)
{
    if(!b) {
        x = 1, y = 0;
        return a;
    }
    LL x1, y1, Gcd;
    Gcd = exgcd(b, a % b, x1, y1);
    x = y1;
    y = x1 - a / b * y1;
    return Gcd;
}
LL inline Mod(LL a, LL b)
{
    return ((a % b) + b) % b;
}
LL EXCRT(LL a[], LL m[], int n)
{
    LL a1 = a[1], m1 = m[1];
    for(int i = 2; i <= n; ++i)
    {
        LL a2 = a[i], m2 = m[i], k1, k2;
        LL d = exgcd(a1, -a2, k1, k2);
        if((m2 - m1) % d)
            return -1;
        LL y = (m2 - m1) / d;
        k1 = Mod(k1 * (m2 - m1) / d, abs(a2 / d));
        m1 = k1 * a1 + m1;
        a1 = abs(a2 / d * a1);
    }
    return m1;
}

另外:

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 50;

LL a[N], m[N];

LL exgcd(LL a, LL b, LL &x, LL &y)
{
    if(!b) {
        x = 1, y = 0;
        return a;
    }
    LL x1, y1, Gcd;
    Gcd = exgcd(b, a % b, x1, y1);
    x = y1;
    y = x1 - a / b * y1;
    return Gcd;
}
LL inline Mod(LL a, LL b)
{
    return ((a % b) + b) % b;
}
LL EXCRT(LL a[], LL m[], int n)
{
    LL a1 = a[1], m1 = m[1];
    for(int i = 2; i <= n; ++i)
    {
        LL a2 = a[i], m2 = m[i], k1, k2;
        LL d = exgcd(a1, -a2, k1, k2);
        if((m2 - m1) % d)
            return -1;
        LL y = (m2 - m1) / d;
        k1 = Mod(k1 * (m2 - m1) / d, abs(a2 / d));
        m1 = k1 * a1 + m1;
        a1 = abs(a2 / d * a1);
    }
    return m1;
}

int main()
{
    int n;
    cin >> n;
    for(int i = 1; i <= n; ++i) cin >> a[i] >> m[i];
    
    cout << EXCRT(a, m, n) << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

W⁡angduoyu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值