题意
给定a,ba,ba,b
求{x≡b1(mod a1)x≡b2(mod a2)x≡b3(mod a3)...x≡bn(mod an)\left\{\begin{matrix}x\equiv b_1(mod\ a_1)
\\ x\equiv b_2(mod\ a_2)
\\ x\equiv b_3(mod\ a_3)
\\...
\\ x\equiv b_n(mod\ a_n)
\end{matrix}\right.⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧x≡b1(mod a1)x≡b2(mod a2)x≡b3(mod a3)...x≡bn(mod an)
xxx的最小非负整数解。
思路
假设已经求出了前k−1k-1k−1个方程构成的方程组的一个解xxx。记mmm为前面所有aia_iai的乘积(代码中mmm为前面所有aia_iai的lcmlcmlcm,不影响后面的结论),则x+i∗m(i∈Z)x+i*m(i \in\mathbb{Z})x+i∗m(i∈Z)是前k−1k-1k−1个方程的通解。
考虑第kkk个方程,求出一个整数ttt使得x+t∗m≡bk(mod ak)x+t*m\equiv b_k(mod\ a_k)x+t∗m≡bk(mod ak)。该方程等价于m∗t≡bk−x(mod ak)m*t\equiv b_k-x(mod\ a_k)m∗t≡bk−x(mod ak),其中ttt是未知量。这就是一个线性同余方程,可以用扩展欧几里得算法判断是否有解,并求出它的解。若有解,则x′=x+t∗mx'=x+t*mx′=x+t∗m就是前kkk个方程构成的方程组的一个解。
故做nnn次exgcdexgcdexgcd可得出答案。
代码
#include<cstdio>
#include<algorithm>
int n;
long long x, y;
long long a[100001], b[100001];
long long exgcd(long long a, long long b, long long &x, long long &y) {
if (!b) {
x = 1;
y = 0;
return a;
}
long long d = exgcd(b, a % b, x, y);
long long z = x;
x = y;
y = z - y * (a / b);
return d;
}
long long mul(long long a, long long b, long long p) {
long long ans = 0;
for (; b; b >>= 1) {
if (b & 1) ans = (ans + a) % p;
a = a * 2 % p;
}
return ans;
}
long long excrt() {
long long m = a[1], ans = b[1];
for (int i = 2; i <= n; i++) {
long long c = ((b[i] - ans) % a[i] + a[i]) % a[i], d = exgcd(m, a[i], x, y);//求解方程mt+ya[k]=(m,a[k])
if (c % d) return -1;//有解当且仅当(m,a[k])|b[k]-x
long long k = a[i] / d;
x = mul(x, c / d, k);//求解方程mt+ya[k]=b[k]-x
ans = ans + x * m;
m *= a[i] / d;
}
return (ans % m + m) % m;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%lld %lld", &a[i], &b[i]);
printf("%lld", excrt());
}