问题
看到这个问题感觉很难???
不用怕,往下看就好啦
假如你不会CRT也没关系
EXCRT大致思路
先考虑将方程组两两联立解开,如先解第一个与第二个,再用第一个与第二个的通解来解第三个...(以此类推)
那么怎么解第一个与第二个同余方程呢?
[egin{cases}
x equiv a_1 pmod{b_1}\
x equiv a_2 pmod{b_2}\
.
.
.
end{cases}
]
则存在整数(注意不是非负),使得
[egin{cases}
x = a_1 +k_1 * b_1\
x = a_2 +k_2 * b_2\
end{cases}
]
所以有
$ a_1 +k_1*b_1$ (=) $a_2 +k_2 * b_2 $
移项可得
$ k_1*b_1 $ (+) $k_2*b_2=a_2-a_1 $
(注意这里可以是 $ k_1*b_1$ (+) $k_2*b_2 $ 因为 $ k_2 $ 可为负数)
不妨令(a_2-a_1)为(c)
然后发现这里长得很像我们的 扩展欧几里得 !!!
而根据裴蜀定理得,当且仅当 $gcd( k_1 , k_2 ) | c $ 时 该方程有整数解
所以我们可用exgcd求出 $ k_1*b_1+k_2*b_2=gcd(k_1,k_2) $
再等式两边同时乘以 $ c/gcd(k_1,k_2) $ 即可
这样就可以解出 此时的式子了
所以新的 A 为(a_1+b_1*k_1) ,新的B则为(lcm(b_1,b_2))
然后再用新的A,B与(a_3,b_3)去计算就好
最后的答案就是最后算出来的A
代码
#include<bits/stdc++.h>
using namespace std;
#define re register
#define int __int128
#define in inline
#define get getchar()
in int read()
{
int t=0; char ch=get;
while(ch<'0' || ch>'9') ch=get;
while( ch<='9' && ch>='0') t=t*10+ch-'0', ch=get;
return t;
}
const int _=2e5+5;
int a[_],b[_],n;
void out(int x) {
if (!x) return;
out(x / 10);
putchar(x % 10 + '0');
}
in int exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1,y=0;
return a;
}
int g=exgcd(b,a%b,y,x);
y -= a / b * x;
return g;
}
in int mul(int a,int b,int mod)
{
int res=0;
while(b)
{
if(b&1)res=(res+a)%mod;
a=(a+a)%mod,b>>=1;
}
return res;
}
in int excrt()
{
int a1=a[1],b1=b[1];
for(re int i=2;i<=n;i++)
{
int a2=a[i],b2=b[i],x,y,c;
c=((a2-a1)%b2+b2)%b2;
int gcd=exgcd(b1,b2,x,y);
if(c%gcd) return -1;
x=mul(x,c/gcd,b2);
a1=a1+x*b1;
b1=b1*b2/gcd;
a1=(a1%b1+b1)%b1;
}
return a1;
}
signed main()
{
n=read();
for(re int i=1;i<=n;i++)
b[i]=read(),a[i]=read();
out(excrt());
return 0;
}