【模板】扩展中国剩余定理(EXCRT)
只需要考虑合并两个方程的情况即可。
$$
\begin{cases}
x \equiv a _ 1 \pmod { m _ 1 }
\\
x \equiv a _ 2 \pmod { m _ 2 }
\end{cases}
$$
对于这样的方程组,我们设:
$$ x = m _ 1 p + a _ 1 = m _ 2 q + a _ 2 $$
那么就会有二元不定方程:
$$ m _ 1 p - m _ 2 q = a _ 2 - a _ 1 $$
那么显然,在 $\gcd ( m _ 1 , m _ 2 ) \nmid ( a _ 2 - a _ 1 )$ 的时候是无解的。
反之我们能解出来对应的 $p , q $。
那么显然得到的解是 $x \equiv b \pmod { M }$。
其中的 $b = m _ 1 p + a _ 1 , M = \operatorname{lcm} (m _ 1 , m _ 2 )$。
时间复杂度 $O( n \log a)$。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| #include<iostream> #include<cstdio> #define ll __int128 using namespace std; namespace Ehnaev{ inline ll read() { ll ret=0,f=1;char ch=getchar(); while(ch<48||ch>57) {if(ch==45) f=-f;ch=getchar();} while(ch>=48&&ch<=57) {ret=(ret<<3)+(ret<<1)+ch-48;ch=getchar();} return ret*f; } inline void write(ll x) { static char buf[22];static ll len=-1; if(x>=0) {do{buf[++len]=x%10+48;x/=10;}while(x);} else {putchar(10);do{buf[++len]=-(x%10)+48;x/=10;}while(x);} while(len>=0) putchar(buf[len--]); } }using Ehnaev::read;using Ehnaev::write;
const ll N=1e5;
ll n,M,b; ll a[N+5],m[N+5];
inline ll Exgcd(ll a,ll b,ll &x,ll &y) { if(b==0) {x=1;y=0;return a;}ll r=Exgcd(b,a%b,y,x);y-=a/b*x;return r; }
int main() {
n=read();
for(ll i=1;i<=n;i++) { m[i]=read();a[i]=read(); } M=m[1];b=a[1];
for(ll i=2;i<=n;i++) { ll m1,m2;m1=M;m2=m[i]; ll d,x0,y0;d=Exgcd(m1,m2,x0,y0); x0=x0*(a[i]-b)/d;y0=y0*(a[i]-b)/d; b=m1*x0+b;M=m1/d*m2; if(b<0) {b=(b+(-b/M+1)*M)%M;} b%=M; }
write(b); return 0; }
|