题意
给定
a
,
b
a,b
a,b
求
{
x
≡
b
1
(
m
o
d
a
1
)
x
≡
b
2
(
m
o
d
a
2
)
x
≡
b
3
(
m
o
d
a
3
)
.
.
.
x
≡
b
n
(
m
o
d
a
n
)
\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)
x
x
x的最小非负整数解。
思路
假设已经求出了前 k − 1 k-1 k−1个方程构成的方程组的一个解 x x x。记 m m m为前面所有 a i a_i ai的乘积(代码中 m m m为前面所有 a i a_i ai的 l c m lcm lcm,不影响后面的结论),则 x + i ∗ m ( i ∈ Z ) x+i*m(i \in\mathbb{Z}) x+i∗m(i∈Z)是前 k − 1 k-1 k−1个方程的通解。
考虑第 k k k个方程,求出一个整数 t t t使得 x + t ∗ m ≡ b k ( m o d a k ) x+t*m\equiv b_k(mod\ a_k) x+t∗m≡bk(mod ak)。该方程等价于 m ∗ t ≡ b k − x ( m o d a k ) m*t\equiv b_k-x(mod\ a_k) m∗t≡bk−x(mod ak),其中 t t t是未知量。这就是一个线性同余方程,可以用扩展欧几里得算法判断是否有解,并求出它的解。若有解,则 x ′ = x + t ∗ m x'=x+t*m x′=x+t∗m就是前 k k k个方程构成的方程组的一个解。
故做 n n n次 e x g c d exgcd exgcd可得出答案。
代码
#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());
}