中国剩余定理
求解模线性方程组。
{x1≡a1(modr1)x2≡a2(modr2)⋯xk≡ak(modrk)" role="presentation" style="text-align: center; position: relative;">⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪x1≡a1(modr1)x2≡a2(modr2)⋯xk≡ak(modrk)
crt
当 r1,r2,⋯,rk" role="presentation" style="position: relative;">r1,r2,⋯,rk 为互质的,设 M=∏i=1kri,Ai=Mri" role="presentation" style="position: relative;">M=∏ki=1ri,Ai=Mri ,可的 M" role="presentation" style="position: relative;">M 是 r1,⋯,rk" role="presentation" style="position: relative;">r1,⋯,rk 的 lcm
可得 Ai,ri" role="presentation" style="position: relative;">Ai,ri 是互质的,则必存在 Ai" role="presentation" style="position: relative;">Ai 模 ri" role="presentation" style="position: relative;">ri 意义下的逆元 ti" role="presentation" style="position: relative;">ti 使得 Aiti≡1(modri)" role="presentation" style="position: relative;">Aiti≡1(modri)
解 xi=aiAiti" role="presentation" style="position: relative;">xi=aiAiti 是满足第 i" role="presentation" style="position: relative;">i 个方程的。同时 ∀j≠i" role="presentation" style="position: relative;">∀j≠i ,都有 xi≡0(modrj)" role="presentation" style="position: relative;">xi≡0(modrj) ,因为 Ai" role="presentation" style="position: relative;">Ai 中有一个因子 rj" role="presentation" style="position: relative;">rj
可以得到通解 x=∑i=1kaiAiti+pM(p∈Z)" role="presentation" style="position: relative;">x=∑ki=1aiAiti+pM(p∈Z) 。显然满足条件
typedef unsigned long long uLL;
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) {
LL a[N], r[N], mul = 1, A[N], ans;
for (int i = 1; i <= n; i++) scanf("%lld%lld", &r[i], &a[i]), mul *= r[i];
for (int i = 1; i <= n; i++) {
ans += a[i] * A[i] * inv(A[i], r[i]);
printf("%lld", ans % mul);
excrt
当 r1,⋯,rk" role="presentation" style="position: relative;">r1,⋯,rk 不互质,此时使用扩展 crt
{x1≡a1(modr1)x2≡a2(modr2)⋯xk≡ak(modrk)" role="presentation" style="text-align: center; position: relative;">⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪x1≡a1(modr1)x2≡a2(modr2)⋯xk≡ak(modrk)
看前两个方程。
x=k⋅r1+a1=p⋅r2+a2" role="presentation" style="position: relative;">x=k⋅r1+a1=p⋅r2+a2 ,其中 k,p∈Z" role="presentation" style="position: relative;">k,p∈Z
k⋅r1−p⋅r2=a2−a1" role="presentation" style="position: relative;">k⋅r1−p⋅r2=a2−a1 ,这是形如 ax+by=c" role="presentation" style="position: relative;">ax+by=c 的形式,用 exgcd 求解。
此处可得 gcd(r1,r2)∤(a2−a1)" role="presentation" style="position: relative;">gcd(r1,r2)∤(a2−a1) 时无解。
求出一个解 k0" role="presentation" style="position: relative;">k0 ,则通解 k=k0+o∗r2gcd(r1,r2)(o∈Z)" role="presentation" style="position: relative;">k=k0+o∗r2gcd(r1,r2)(o∈Z)
将 k" role="presentation" style="position: relative;">k 带入 k⋅r1+a1" role="presentation" style="position: relative;">k⋅r1+a1 可得
(k0+o∗r2gcd(r1,r2))⋅r1+a1=k0∗r1+a1+o∗lcm(r1,r2)" role="presentation" style="text-align: center; position: relative;">(k0+o∗r2gcd(r1,r2))⋅r1+a1=k0∗r1+a1+o∗lcm(r1,r2)
即 x≡k0∗r1+a1(modlcm(r1,r2))" role="presentation" style="position: relative;">x≡k0∗r1+a1(modlcm(r1,r2))
相当于合并了两个方程,合并 n−1" role="presentation" style="position: relative;">n−1 次即可得到答案。
注意 k0" role="presentation" style="position: relative;">k0 应乘上 a2−a1gcd(r1,r2)" role="presentation" style="position: relative;">a2−a1gcd(r1,r2)
模板题需要用龟速乘。
typedef unsigned long long uLL;
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 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) {
for (int i = 1; i <= n; i++) scanf("%lld%lld", &r[i], &a[i]);
for (int i = 1; i < n; i++) {
if (!sol(r[i], r[i + 1], a[i + 1] - a[i], x, y)) {
a[i + 1] = x * r[i] + a[i];
r[i + 1] = r[i] / G * r[i + 1];