Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // This is a collection of useful code for solving problems that
- // involve modular linear equations. Note that all of the
- // algorithms described here work on nonnegative integers.
- #include <iostream>
- #include <vector>
- #include <algorithm>
- using namespace std;
- typedef vector<long long> VI;
- typedef pair<long long, long long> PII;
- // return a % b (positive value)
- long long mod(long long a, long long b) {
- return ((a%b) + b) % b;
- }
- // computes gcd(a,b)
- long long gcd(long long a, long long b) {
- while (b) { long long t = a%b; a = b; b = t; }
- return a;
- }
- // computes lcm(a,b)
- long long lcm(long long a, long long b) {
- return a / gcd(a, b)*b;
- }
- // (a^b) mod m via successive squaring
- long long powermod(long long a, long long b, long long m)
- {
- long long ret = 1;
- while (b)
- {
- if (b & 1) ret = mod(ret*a, m);
- a = mod(a*a, m);
- b >>= 1;
- }
- return ret;
- }
- // returns g = gcd(a, b); finds x, y such that d = ax + by
- long long extended_euclid(long long a, long long b, long long &x, long long &y) {
- long long xx = y = 0;
- long long yy = x = 1;
- while (b) {
- long long q = a / b;
- long long 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(long long a, long long b, long long n) {
- long long x, y;
- VI ret;
- long long g = extended_euclid(a, n, x, y);
- if (!(b%g)) {
- x = mod(x*(b / g), n);
- for (long long i = 0; i < g; i++)
- ret.push_back(mod(x + i*(n / g), n));
- }
- return ret;
- }
- // computes b such that ab = 1 (mod n), returns -1 on failure
- long long mod_inverse(long long a, long long n) {
- long long x, y;
- long long g = extended_euclid(a, n, x, y);
- if (g > 1) return -1;
- return mod(x, n);
- }
- // 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(long long m1, long long r1, long long m2, long long r2) {
- long long s, t;
- long long 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 (long long 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;
- }
- // computes x and y such that ax + by = c
- // returns whether the solution exists
- bool linear_diophantine(long long a, long long b, long long c, long long &x, long long &y) {
- if (!a && !b)
- {
- if (c) return false;
- x = 0; y = 0;
- return true;
- }
- if (!a)
- {
- if (c % b) return false;
- x = 0; y = c / b;
- return true;
- }
- if (!b)
- {
- if (c % a) return false;
- x = c / a; y = 0;
- return true;
- }
- long long g = gcd(a, b);
- if (c % g) return false;
- x = c / g * mod_inverse(a / g, b / g);
- y = (c - a*x) / b;
- return true;
- }
- int main() {
- // expected: 2
- cout << gcd(14, 30) << endl;
- // expected: 2 -2 1
- long long x, y;
- long long g = extended_euclid(14, 30, x, y);
- cout << g << " " << x << " " << y << endl;
- // expected: 95 451
- VI sols = modular_linear_equation_solver(14, 30, 100);
- for (int i = 0; i < sols.size(); i++) cout << sols[i] << " ";
- cout << endl;
- // expected: 8
- cout << mod_inverse(8, 9) << endl;
- // expected: 23 105
- // 11 12
- PII ret = chinese_remainder_theorem(VI({ 3, 5, 7 }), VI({ 2, 3, 2 }));
- cout << ret.first << " " << ret.second << endl;
- ret = chinese_remainder_theorem(VI({ 4, 6 }), VI({ 3, 5 }));
- cout << ret.first << " " << ret.second << endl;
- // expected: 5 -15
- if (!linear_diophantine(7, 2, 5, x, y)) cout << "ERROR" << endl;
- cout << x << " " << y << endl;
- return 0;
- }
Add Comment
Please, Sign In to add comment