问题
求满足: \[ \begin{aligned} x &\equiv b_1 &\pmod{a_1} \\ x &\equiv b_2 &\pmod{a_2} \\ x &\equiv b_3 &\pmod{a_3} \\ &\ \ \vdots &\\ x &\equiv b_n &\pmod{a_n} \end{aligned} \] 的 \(x\) 的值。
ExCRT
当 \(a_1, a_2, \cdots, a_n\) 互素的时候显然可以使用中国剩余定理(CRT)解决,时间复杂度为 \(O(n\log n)\)。
考虑不互素的情况,假设已经解决了前 \(i - 1\) 个方程,得到的解为 \(x_{i - 1}\),\(\operatorname{lcm}(a_1, \cdots, a_{i - 1}) = m\)。
那么我们考虑解决 \[ x_{i - 1} + tm \equiv b_i \pmod{a_i} \] 易证得到的解 \(x_i = x_{i - 1} + tm\) 不会再和前 \(i\) 个解产生冲突。
稍微移项一下: \[ tm \equiv b_i - x_{i - 1} \pmod{a_i} \] 用 ExGCD 解出 \(t\) 即可。
这套方法称为 ExCRT(拓展中国剩余定理),复杂度依旧是 \(O(n\log n)\)。全面优于 CRT。
代码:
#include <cstdio>
using namespace std;
typedef long long ll;
const int N = 100010;
int n;
[N], b[N];
ll a
(ll a, ll b, ll &x, ll &y) {
ll exgcdif (b == 0) return x = 1, y = 0, a;
= exgcd(b, a % b, y, x);
ll d return y -= a / b * x, d;
}
(ll x, ll y, ll mod) {
ll smulif (y < 0) return -qmul(x, -y, mod);
= 0;
ll ret for (; y; y >>= 1) {
if (y & 1) ret = (ret + x) % mod;
= (x + x) % mod;
x }
return ret;
}
() {
ll excrt= a[1], t = b[1], x, y;
ll lcm for (int i = 2; i <= n; i++) {
= exgcd(lcm, a[i], x, y);
ll d = smul(x, (b[i] - t) / d, a[i]);
x += x * lcm;
t = lcm / d * a[i];
lcm = (t % lcm + lcm) % lcm;
t }
return t;
}
int main() {
("%d", &n);
scanffor (int i = 1; i <= n; i++) scanf("%lld%lld", &a[i], &b[i]);
("%lld\n", excrt());
printfreturn 0;
}