-
Notifications
You must be signed in to change notification settings - Fork 3
/
euclid.cpp
59 lines (53 loc) · 1.58 KB
/
euclid.cpp
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
typedef vector<int> VI;
typedef pair<int, int> PII;
// computes gcd(a,b)
int gcd(int a, int b) {
while (b) { int t = a%b; a = b; b = t; }
return a;
}
// returns g = gcd(a, b); finds x, y such that d = ax + by
int extended_euclid(int a, int b, int &x, int &y) {
int xx = y = 0;
int yy = x = 1;
while (b) {
int q = a / b;
int t = b; b = a%b; a = t;
t = xx; xx = x - q*xx; x = t;
t = yy; yy = y - q*yy; y = t;
}
return a;
}
// finds all solutions to ax = b (mod n)
VI modular_linear_equation_solver(int a, int b, int n) {
int x, y;
VI ret;
int g = extended_euclid(a, n, x, y);
if (!(b%g)) {
x = mod(x*(b / g), n);
for (int i = 0; i < g; i++)
ret.push_back(mod(x + i*(n / g), n));
}
return ret;
}
// Chinese remainder theorem (special case): find z such that
// z % m1 = r1, z % m2 = r2. Here, z is unique modulo M = lcm(m1, m2).
// Return (z, M). On failure, M = -1.
PII chinese_remainder_theorem(int m1, int r1, int m2, int r2) {
int s, t;
int g = extended_euclid(m1, m2, s, t);
if (r1%g != r2%g) return make_pair(0, -1);
return make_pair(mod(s*r2*m1 + t*r1*m2, m1*m2) / g, m1*m2 / g);
}
// Chinese remainder theorem: find z such that
// z % m[i] = r[i] for all i. Note that the solution is
// unique modulo M = lcm_i (m[i]). Return (z, M). On
// failure, M = -1. Note that we do not require the a[i]'s
// to be relatively prime.
PII chinese_remainder_theorem(const VI &m, const VI &r) {
PII ret = make_pair(r[0], m[0]);
for (int i = 1; i < m.size(); i++) {
ret = chinese_remainder_theorem(ret.second, ret.first, m[i], r[i]);
if (ret.second == -1) break;
}
return ret;
}