我 tm……CRT 没看懂 exCRT 却看懂了……emmmm……
而且这名字完全就是国内的 OI 带师胡起的吧……
考虑一次同余方程组 \[\begin{cases} x \equiv a_1\ ({\rm mod}\ m_1) \\ x\equiv a_2\ ({\rm mod}\ m_2) \\ ... \\ x \equiv a_n\ ({\rm mod}\ m_n)\end{cases}\] 的解的问题。
CRT 成立的前提是 \(\gcd\{m_n\}=1\)。这里不一定保证这个条件。
原理还是很简单的,利用归纳法,考虑前 \(k-1\) 个方程组的解为 \(x\),并记 \(m={\rm lcm}(m_1,\dots,m_{k-1})\),那么对于第 \(k\) 个方程,就是找一个 \(t\in\mathbb{Z}\),使得 \(x+tm\equiv a_k\pmod{m_k}\)。把 \(x\) 扔到右边就是一个 \(tm\equiv a_k-x\pmod{m_k}\),可以用 exgcd 求了。
所以纵观整个算法其实是一个不断用 exgcd 迭代的过程。
好,理论说完了,来到毒瘤代码环节……这玩意……真心没办法言传……我看了好久才会orz……
把关键部分注释一下:
int main()
{
scanf("%d",&n);
ll M,ans,x,y,k; scanf("%lld%lld",&M,&ans);
for(int i=1;i<n;++i)
{
ll at,mt; scanf("%lld%lld",&at,&mt);
ll a=M,b=at,c=(mt-ans%b+b)%b;
ll gcd=exgcd(a,b,x,y),bg=b/gcd;
if(c%gcd!=0) {puts("-1"); return 0;}
x=smul(x,c/gcd,bg);
ans+=x*M; M*=bg;
ans=(ans%M+M)%M;
}
printf("%lld",(ans%M+M)%M);
return 0;
}