中国剩余定理
求解模线性方程组。
crt
当 \(r_1,r_2,\cdots,r_k\) 为互质的,设 \(M=\prod_{i=1}^k r_i,A_i=\dfrac{M}{r_i}\) ,可的 \(M\) 是 \(r_1,\cdots,r_k\) 的 lcm
可得 \(A_i,r_i\) 是互质的,则必存在 \(A_i\) 模 \(r_i\) 意义下的逆元 \(t_i\) 使得 \(A_it_i\equiv 1\pmod{r_i}\)
解 \(x_i=a_iA_it_i\) 是满足第 \(i\) 个方程的。同时 \(\forall j\ne i\) ,都有 \(x_i\equiv 0\pmod{r_j}\) ,因为 \(A_i\) 中有一个因子 \(r_j\)
可以得到通解 \(x=\sum_{i=1}^k a_i A_i t_i+pM(p\in\mathbb{Z})\) 。显然满足条件
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long uLL;
typedef long double LD;
typedef long long LL;
typedef double db;
const int N = 55;
LL exgcd(LL a, LL b, LL &x, LL &y) {
if (!b) return x = 1, y = 0, a;
register LL gcd = exgcd(b, a % b, y, x);
return y -= a / b * x, gcd;
}
inline LL inv(LL a, LL b) {
register LL x, y;
exgcd(a, b, x, y);
return (x % b + b) % b;
}
int n;
LL a[N], r[N], mul = 1, A[N], ans;
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%lld%lld", &r[i], &a[i]), mul *= r[i];
for (int i = 1; i <= n; i++) {
A[i] = mul / r[i];
ans += a[i] * A[i] * inv(A[i], r[i]);
}
printf("%lld", ans % mul);
}
excrt
当 \(r_1,\cdots,r_k\) 不互质,此时使用扩展 crt
看前两个方程。
\(x=k\cdot r_1+a_1=p\cdot r_2+a_2\) ,其中 \(k,p\in\mathbb{Z}\)
\(k\cdot r_1-p\cdot r_2=a_2-a_1\) ,这是形如 \(ax+by=c\) 的形式,用 exgcd 求解。
此处可得 \(\gcd(r_1,r_2)\nmid (a_2-a_1)\) 时无解。
求出一个解 \(k_0\) ,则通解 \(k=k_0+o*\dfrac{r_2}{\gcd(r_1,r_2)}(o\in\mathbb{Z})\)
将 \(k\) 带入 \(k\cdot r_1+a_1\) 可得
即 \(x\equiv k_0*r_1+a_1\pmod{\text{lcm}(r_1,r_2)}\)
相当于合并了两个方程,合并 \(n-1\) 次即可得到答案。
注意 \(k_0\) 应乘上 \(\dfrac{a_2-a_1}{\gcd(r_1,r_2)}\)
模板题需要用龟速乘。
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long uLL;
typedef long double LD;
typedef long long LL;
typedef double db;
const int N = 100005;
LL exgcd(LL a, LL b, LL &x, LL &y) {
if (!b) return x = 1, y = 0, a;
register LL gcd = exgcd(b, a % b, y, x);
return y -= a / b * x, gcd;
}
LL G;
inline LL mul(LL x, LL y, LL p) {
return (x * y - (LL)((LD)x / p * y) * p + p) % p;
}
inline bool sol(LL a, LL b, LL c, LL &x, LL &y) {
G = exgcd(a, b, x, y);
register LL t;
if (c % G) return false;
t = b / G;
x = mul(x, c / G, t);
x = (x + t) % t;
y = (c - a * x) / b;
return true;
}
int n, isL;
LL a[N], r[N];
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%lld%lld", &r[i], &a[i]);
isL = 1;
for (int i = 1; i < n; i++) {
register LL x, y;
if (!sol(r[i], r[i + 1], a[i + 1] - a[i], x, y)) {
isL = 0; break;
}
a[i + 1] = x * r[i] + a[i];
r[i + 1] = r[i] / G * r[i + 1];
}
printf("%lld", a[n]);
}