发布时间 2023-07-16 19:45:00作者: SoyTony

有些东西特别爱忘,所以在这写一下。

EXCRT

首先会了 EXCRT 就可以不用会 CRT 了,感觉 EXCRT 或许好会。

有线性同余方程组:

\[\begin{cases} x\equiv& a_1\pmod {b_1}\\ x\equiv& a_2\pmod {b_2}\\ &\vdots\\ x\equiv& a_n\pmod {b_n}\\ \end{cases}\]

推导解法。

取出前两个式子,可以表示成:

\[x=k_1b_1+a_1=k_2b_2+a_2 \]

这样移项处理成:

\[b_1k_1-b_2k_2=a_2-a_1 \]

\(x_0=k1,y_0=k2\),那么有:

\[b_1x_0-b_2y_0=a_2-a_1 \]

可以 exgcd 解出 \(x\),注意是在 \(\dfrac{b_2}{\gcd(b_1,b_2)}\) 意义下的。

之后任意解可以写作 \(x_0+\dfrac{b_2}{\gcd(b_1,b_2)}\times k\)

代回去:

\[x=b_1x_0+\dfrac{b_1b_2}{\gcd(b_1,b_2)}\times k+a_1 \]

改写后是:

\[x=b_1x_0+a_1+k\mathrm{lcm}(b_1,b_2) \]

于是合并成了:

\[x\equiv b_1x_0+a_1 \pmod{\mathrm{lcm}(b_1,b_2)} \]

讲真这个推导过程我学了快两年第一次看。

点击查看代码
inline ll mul(ll A,ll B,ll P){
    ll res=0;
    while(B){
        if(B&1) res=(res+A)%P;
        A=(A+A)%P;
        B>>=1;
    }
    return res;
}
ll exgcd(ll A,ll B,ll &X,ll &Y){
    if(!B){
        X=1,Y=0;
        return A;
    }
    ll D=exgcd(B,A%B,Y,X);
    Y-=A/B*X;
    return D;
}

int n;
ll a[maxn],b[maxn];

inline void EXCRT(){
    ll A=a[1],B=b[1];
    for(int i=2;i<=n;++i){
        ll X,Y;
        ll D=exgcd(B,b[i],X,Y),BD=b[i]/D;
        X=(X%BD+BD)%BD;
        X=mul(X,((a[i]-A)/D%BD+BD)%BD,BD);
        ll tmp=BD*B;
        A=(mul(X,B,tmp)+A)%tmp;
        B=tmp;
    }
    printf("%lld\n",A);
}