Everything here is extended Euclid (GCD and Extended Euclid) plus careful division. Modular inverses: exists iff (invMod); for primes and batch inverses see Modular Arithmetic.

Linear congruences and the CRT

is solvable iff divides , and then the solutions form one class modulo (that is, classes modulo — forgetting there are of them, not one, is the usual mistake when a problem asks for a count or the smallest positive solution). A system is solvable iff for all pairs, and the solution is unique modulo .

Related equationMethod
over linear Diophantine, below
quadratic residues, Tonelli–Shanks (Modular Square Roots)
discrete logarithm (Primitive Roots and Discrete Log)
discrete root (same note)
solve mod , then Hensel lift (Modular Square Roots)
pair<ll, ll> linearCongruence(ll a, ll b, ll m) {          // {x0, step}: solutions x0 + k*step; {-1, -1} if none
    a = ((a % m) + m) % m; b = ((b % m) + m) % m;
    ll x, y, g = extgcd(a, m, x, y);
    if (b % g) return {-1, -1};
    ll md = m / g, x0 = (ll)((__int128)((x % md + md) % md) * (b / g) % md);
    return {x0, md};
}
pair<ll, ll> crtMerge(ll r1, ll m1, ll r2, ll m2) {        // x = r1 (m1), x = r2 (m2) -> {r, lcm}; {-1, -1} if inconsistent
    ll p, q, g = extgcd(m1, m2, p, q);
    if ((r2 - r1) % g) return {-1, -1};
    ll l = m1 / g * m2;                                     // assumes lcm fits in ll
    ll t = (ll)((__int128)((r2 - r1) / g) * p % (m2 / g));
    ll r = (ll)(((__int128)m1 * t + r1) % l); if (r < 0) r += l;
    return {r, l};
}
pair<ll, ll> crt(const vector<ll>& r, const vector<ll>& m) {
    pair<ll, ll> cur{0, 1};
    for (int i = 0; i < sz(r) && cur.second != -1; i++) cur = crtMerge(cur.first, cur.second, ((r[i] % m[i]) + m[i]) % m[i], m[i]);
    return cur;
}
ll garner(const vector<ll>& r, const vector<ll>& m, ll mod) {   // pairwise coprime m_i; x mod `mod` (x < prod m_i)
    int k = sz(r); vector<ll> M = m; M.push_back(mod);
    vector<ll> coef(k + 1, 1), cst(k + 1, 0);              // for each modulus: value of prod_{j<i} m_j and of the partial sum
    for (int i = 0; i < k; i++) {
        ll t = ((r[i] - cst[i]) % m[i] + m[i]) % m[i];
        t = (ll)((__int128)t * invMod(coef[i], m[i]) % m[i]);   // the i-th mixed-radix digit
        for (int j = i + 1; j <= k; j++) cst[j] = (ll)((cst[j] + (__int128)t * coef[j]) % M[j]), coef[j] = (ll)((__int128)coef[j] * m[i] % M[j]);
    }
    return cst[k];
}

Garner is the tool when the true value exceeds 64 bits but is wanted modulo something: combining NTTs over three primes into a result modulo , or reconstructing big integers digit by digit.

Linear Diophantine equations

has integer solutions iff ; from one solution all are , . Constrained versions (count in a box, smallest non-negative , minimise ) intersect intervals of with exact floor / ceiling division: (and symmetrically for , or both at once by intersecting); since is linear in , minimising over a feasible range of means pushing to whichever end of its interval the sign of favours and checking both endpoints.

Floor division with negatives

C++ truncates toward zero, so (-7) / 2 == -3, not . Use explicit floorDiv/ceilDiv helpers for every -range computation above — nearly every wrong answer in this topic traces back to plain / on a negative numerator.

bool diophantine(ll a, ll b, ll c, ll& x, ll& y, ll& g) {   // one solution of a x + b y = c (a, b not both 0)
    g = extgcd(a, b, x, y);                                // extgcd keeps signs: a x + b y = g
    if (c % g) return false;
    x = (ll)((__int128)x * (c / g)); y = (ll)((__int128)y * (c / g));
    return true;
}
ll countSolutions(ll a, ll b, ll c, ll xl, ll xr, ll yl, ll yr) {   // a, b != 0; x in [xl, xr], y in [yl, yr]
    ll x, y, g; if (!diophantine(a, b, c, x, y, g)) return 0;
    ll dx = b / g, dy = -a / g;                            // x + k dx, y + k dy
    auto range = [&](ll v, ll d, ll lo, ll hi, ll& kl, ll& kr) {   // lo <= v + k d <= hi
        if (d > 0) kl = ceilDiv(lo - v, d), kr = floorDiv(hi - v, d);
        else kl = ceilDiv(hi - v, d), kr = floorDiv(lo - v, d);
    };
    ll a1, b1, a2, b2; range(x, dx, xl, xr, a1, b1); range(y, dy, yl, yr, a2, b2);
    return max(0LL, min(b1, b2) - max(a1, a2) + 1);
}
FactValue
several variables solvable iff ; solve by folding two coefficients into their gcd
Frobenius number of coprime (the Chicken McNugget theorem)the largest non-representable (with ) is
non-representable countexactly
non-negative solutions of ( coprime) or
many coins (Frobenius in general)no closed form, and computing the Frobenius number is NP-hard — use shortest paths on residues modulo the smallest coin instead, which answers representability for targets up to (Shortest Path Techniques)

Where these show up

Problem framingReduces to
jug pouring / measuring, “can I make exactly with steps of and ?”, non-negative for the measuring version
modular division , i.e.
lattice points on a line segment points, from the same Bézout theory
two events repeating every steps, when do they coincideCRT, which itself reduces to a Diophantine equation
scheduling / cyclic constraints with two step sizescount solutions of in a range