中国剩余定理

一组线性同余方程组

形如:\(\begin{array}{l} \left\{\begin{matrix} x \equiv a_1\ (\ mod\ m_1) \\ x \equiv a_2\ (\ mod\ m_2) \\ ...\\ ...\\ x \equiv a_n\ (\ mod\ m_n) \end{matrix}\right. \end{array}\)

\(CRT\)

1、条件:方程组中的 \(m_1,m_2,...,m_n\) 两两互质,现在我们令 \(M=m_1·m_2·...·m_n\),我们再令 \(M_i=M/m_i\),定义 \(t_i\) 为每个 \(M_i\) 模上 \(m_i\) 下的逆元,即满足 \(M_i·t_i\equiv 1\ (\ mod\ m_i)\),那么我们就可以构造出一组解 \(x_0=\sum_{i=1}^{n}a_i·M_i·t_i\),那么就有:

\(\left\{\begin{matrix} a_j·M_j·t_j\% m_i=0,j\ne i \\ a_j·M_j·t_j\% m_i=a_i,j=i \end{matrix}\right.\)

所以就使所有线性同余方程组都满足 \(x_0\% m_i=a_i\),这个是特解。

2、特解:\(x_0=\sum_{i=1}^{n}a_i·M_i·t_i\)

3、通解:\(x=x_0+k·M(k=1,2,3,...)\),其中最小整数解 \(ans=x\%M\)

4、题目链接:洛谷P1495

void exgcd(i128 a, i128 b, i128 &x, i128 &y) {
    if (!b) {
        x = 1;
        y = 0;
        return;
    }

    exgcd(b, a % b, y, x);
    y -= a / b * x;
}

void solve()
{
    int n;
    cin >> n;
    vector<i128> a(n + 1), md(n + 1);
    i128 M = 1;
    for (int i = 1; i <= n; i++) {
        read(a[i], md[i]);
        M *= a[i];
    }

    vector<i128> m(n + 1), t(n + 1);
    for (int i = 1; i <= n; i++) {
        m[i] = M / a[i];
        i128 y;
        exgcd(m[i], a[i], t[i], y);
        t[i] %= a[i];
        t[i] = (t[i] + a[i]) % a[i];
    }

    i128 ans = 0;
    for (int i = 1; i <= n; i++) {
        ans = (ans + (md[i] * m[i] % M * t[i] % M)) % M;
    }
    ans = (ans + M) % M;
    write(ans, '\n');
}

EXCRT

1、和 \(crt\) 的区别就是不满足所有的 \(m_i\) 两两之间互质了,解决方法也很简单,首先假设我们有 \(k\) 组线性同余方程,现在我们求出了 \(k-1\) 组的通解为 \(x=r1+k1·M,(k1=1,2,3,...)\),现在假设我们找到了一个通解 \(k1=t\),使得 \((r1+t·M)\% m_k=r_2\),那么 \(k\) 组线性同余方程的通解则为 \(x=r1+t·M+k_2·lcm(M,m_k),(i=1,2,3,...)\)

2、另外,如何求解这个 \(t\) 呢,那么就需要用到我们的扩展欧几里得了,我能将式子拆成别的形式,可以得到 \(M·t+m_k·y=r2-r_1\),其中 \(gcd(M,m_k)\ |\ (r_2-r_1)\),如果不满足,则说明无解。现在我们就可以得到通解里面的 \(t=t·\frac{r_2-r_1}{gcd(M,m_k)}\),不过这里得龟速乘,否则会爆 \(longlong\),另外还有个值的注意的是,我们需要将 \(r_2-r_1\) 化为非负数,否则会导致快速乘 \(tle\)

3、题目链接:洛谷P4777

void exgcd(i128 a, i128 b, i128 &x, i128 &y) {
    if (!b) {
        x = 1;
        y = 0;
        return;
    }

    exgcd(b, a % b, y, x);
    y -= a / b * x;
}

void solve()
{
    int n;
    read(n);
    vector<i128> a(n + 1), b(n + 1);
    i128 M, r;
    for (int i = 1; i <= n; i++) {
        read(a[i], b[i]);
        if (i == 1) {
            M = a[i];
            r = b[i];
        }
    }
    for (int i = 2; i <= n; i++) {
        i128 d = __gcd(M, a[i]);
        i128 t, y;
        exgcd(M, a[i], t, y);
        t %= a[i];
        i128 res = b[i] - r;
        assert(res % d == 0);
        t = t * (res / d) % a[i];
        t = (t + a[i]) % a[i];
        i128 LCM = M * a[i] / d;
        r = (r + (t * M % LCM)) % LCM;
        r = (r + LCM) % LCM;
        M = LCM;
    }
    write(r, '\n');
}

具体的详细内容可见这位大佬的博客:传送门

posted @ 2024-09-18 16:08  grape_king  阅读(34)  评论(0)    收藏  举报