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 equation | Method |
|---|---|
| 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.
Proof: congruences, CRT and Garner
Linear congruence: for some , solvable iff (Bézout). Dividing by gives with , so is unique modulo ; the coefficient from extended Euclid on is that inverse modulo .
Merging two congruences: we need , i.e. , solvable iff ; then where . Two solutions differ by a common multiple of and , so the solution is unique modulo . Pairwise consistency suffices for a whole system by induction (the merged modulus is the lcm, and consistency with the next congruence reduces to the pairwise conditions prime by prime).
Garner: write with (mixed radix). Reducing modulo , the terms after vanish, so , invertible by pairwise coprimality. The arrays
cst[j],coef[j]hold the partial sum and the running product reduced modulo , which is all that is needed to compute later digits and the final value modulomod. operations.
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 explicitfloorDiv/ceilDivhelpers 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);
}| Fact | Value |
|---|---|
| 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 count | exactly |
| 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) |
Proof: general solution, and the two-coin Frobenius facts
General solution: if then ; dividing by , and are coprime, so by Euclid’s lemma, giving the parametrisation; conversely every member solves the equation. Counting: each constraint confines to an interval whose ends are exact floor/ceiling quotients (the direction flips when the step is negative); the answer is the length of the intersection.
Frobenius: for coprime , every has a unique representation with (choose ). is representable with non-negative coefficients iff that . The largest with is , and every larger has . Count: the map sends representable numbers in to non-representable ones and vice versa (if both and were representable, so would be their sum ; if neither, the representations with have and with , and adding gives with , forcing and , impossible). So exactly half of the numbers in that range are non-representable. Number of representations: with fixed by the residue, the others are ; the count of with is when , which is or one more.
Where these show up
| Problem framing | Reduces 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 coincide | CRT, which itself reduces to a Diophantine equation |
| scheduling / cyclic constraints with two step sizes | count solutions of in a range |