拓展 CRT

简介

简单捏。

题目

给定 \(2n\) 个整数 \(a_1,a_2,…,a_n\)\(m_1,m_2,…,m_n\),求一个最小的非负整数 \(x\),满足 $ \forall i \in [1,n],x \equiv m_i(mod\ a_i)$。

其中, \(a_{i}\) 并不互质。

解法

显然不能用普通的 CRT,所以考虑重新思考解法。

首先考虑两个同余式。

\[\large \begin{aligned} x &\equiv m_{1}\quad(\mod a_{1}\;\;\:)\\ x &\equiv m_{2}\quad(\mod a_{2}\;\;\:) \end{aligned} \]

考虑改写:

\[\large \begin{aligned} x&=m_1+pa_1\\ x&=m_2+qa_2\\ m_1+pa_1&=m_2+qa_2\\ pa_1-qa_2&=m_2-m_1\\ \end{aligned} \]

\(a_2=-a_2\),我们可以用 EXGCD 求出 \(p,q\),考虑 \(p,q\) 的每一个解:

\[\large \begin{aligned} p'&=p+k \cdot \lvert \frac{a_2}{\gcd(a_1,a_2)}\rvert\\ q'&=q+k \cdot \lvert \frac{a_1}{\gcd(a_1,a_2)}\rvert \end{aligned} \]

考虑表示出 \(x\)

\[\large \begin{aligned} x&=m_1+a_1(p+k\cdot \lvert \frac{a_2}{\gcd(a_1,a_2)}\rvert)\\ x&=m_1+a_1p+k\cdot \lvert \frac{a_1\cdot a_2}{\gcd(a_1,a_2)}\rvert) \end{aligned} \]

此时,\(x\) 的表达式已经形如最开始的表达式了,也就是说,我们将两个合并成了一个。
\(m_1=m_1+pa_1\)\(a_1=\lvert \frac{a_1\cdot a_2}{\gcd(a_1,a_2)}\rvert\),即为新的方程。每次合并都会减少一个方程,最后只有一个的时候答案就是 \(m_1 \mod\;\: a_1\)

考虑到每次的 \(m_1\) 生成中都有 \(p\) 的出现,题目要求我们求的是最小正整数解,所以考虑将 \(p\) 变为最小正整数解,即:

\[\large \begin{aligned} p'=p \mod \;\: \lvert \frac{a_1\cdot a_2}{\gcd(a_1,a_2)}\rvert \end{aligned} \]

Code

#include <bits/stdc++.h>
#define int long long
using namespace std;
int m1,a1,m2,a2,n;
int exgcd(int a,int b,int &x,int &y) {
    if(!b) {
        x=1,y=0;
        return a;
    }
    int d=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}
signed main() {
    cin>>n;
    cin>>a1>>m1;
    for(int i=1;i<n;i++) {
        cin>>a2>>m2;
        int k1,k2;
        int d=exgcd(a1,a2,k1,k2);
        if((m2-m1)%d) {
            puts("-1");
            return 0;
        }
        k1*=(m2-m1)/d;
        k1=(k1%(a2/d)+(a2/d))%(a2/d);
        m1+=a1*k1;
        a1*=a2/d;
    }
    cout<<(m1%a1+a1)%a1<<endl;
    return 0;
}
posted @ 2024-08-21 11:02  PM_pro  阅读(25)  评论(0)    收藏  举报