拓展 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;
}

浙公网安备 33010602011771号