扩展中国剩余定理(exCRT)

我 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;
}
上一篇:第三十三个知识点:Bellcore攻击是如何攻击使用CRT的RSA的?


下一篇:中国剩余定理