前言
数论总是学了就忘,趁着没忘赶紧写出来
扩展中国剩余定理
为什么是扩展呢,因为不扩展的太菜了,从本质上来说,两者的做法有着本质上的区别,CRT 依靠构造,EXCRT 则是合并(由此可见 EXCRT 适用性更广的原因)。而且时间复杂度一样,码量也区别不大,因此可能还是 EXCRT 更好用一点
证明
(注:本文方法和网上的略有不同)
⎩⎨⎧x≡c1(mod m1)x≡c2(mod m2)⋮x≡cn(mod mn)
因为没了 m 两两互质的限制,因此只能用合并解决。
首先拿出两个式子:
x≡c1(mod m1)x≡c2(mod m2)
接着把它们换个形式:
x=k1m1+c1x=k2m2+c2
联立,接着往下推:
k1m1+c1k1m1注:这个方程有解的条件是gcd (m1,m2)k1m1gcd (m1,m2)m1k1gcd (m1,m2)m1k1k1k1x注:这里把k1带入x=k1m1x=k2m2+c2=c2−c1+k2m2gcd (m1,m2)∣(c2−c1),后文会用到=gcd (m1,m2)c2−c1+gcd (m1,m2)k2m2=gcd (m1,m2)c2−c1+gcd (m1,m2)m2k2≡gcd (m1,m2)c2−c1(mod gcd (m1,m2)m2)≡gcd (m1,m2)c2−c1gcd (m1,m2)m1−1(mod gcd (m1,m2)m2)(mod gcd (m1,m2)m2)=gcd (m1,m2)c2−c1gcd (m1,m2)m1−1(mod gcd (m1,m2)m2)+ygcd (m1,m2)m2=gcd (m1,m2)c2−c1gcd (m1,m2)m1−1(mod gcd (m1,m2)m2)m1+ygcd (m1,m2)m1m2+c1+c1中,就可以求出合并后的式子≡gcd (m1,m2)c2−c1gcd (m1,m2)m1−1(mod gcd (m1,m2)m2)m1+c1(mod gcd (m1,m2)m1m2)
到这里,我们就可以得到合并后的式子:
令:
⎩⎨⎧c=gcd (m1,m2)c2−c1gcd (m1,m2)m1−1(mod gcd (m1,m2)m2)m1+c1m=gcd (m1,m2)m1m2
则有:
x≡c(mod m)
照着写就行了……
(一定要给 c,m 赋为最先输入的 不然过不了n=1)
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
|
#include <bits/stdc++.h> #define int __int128 #define FH signed using namespace std;
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
int exgcd(int a, int b, int& x, int& y) { if(!b) { x = 1, y = 0; return a; } int d = exgcd(b, a % b, y, x); y -= a / b * x; return d; }
int inv(int a, int b) { int x, y; exgcd(a, b, x, y); while (x < 0) x += b; return x; }
int read() { int f=1,x=0; char ss=getchar(); while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();} while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();} return f*x; }
FH main() { int n; n = read();
int c1, c2, m1, m2, c, m; m1 = read(), c1 = read(); c = c1, m = m1; for(int i = 2; i <= n; i ++) { m2 = read(), c2 = read(); int d = gcd(m1, m2); if((c2 - c1) % d != 0) { cout << -1; return 0; } m = (m1 * m2) / d; c = (inv(m1 / d, m2 / d) * (c2 - c1) / d) % (m2 / d) * m1 + c1; c = (c % m + m) % m; c1 = c, m1 = m; } cout << (long long)c << "\n"; return 0; }
|