with ; it runs in steps (worst case: consecutive Fibonacci numbers). The extended Euclid algorithm also returns Bézout coefficients , which give modular inverses, linear Diophantine equations and CRT (Congruences and CRT).
ll extgcd(ll a, ll b, ll& x, ll& y) { // returns g = gcd(a, b) >= 0 and a x + b y = g
x = 1, y = 0; ll x1 = 0, y1 = 1; // the quotients q below are exactly a/b's continued-fraction expansion
while (b) { ll q = a / b; tie(a, b) = make_pair(b, a - q * b); tie(x, x1) = make_pair(x1, x - q * x1); tie(y, y1) = make_pair(y1, y - q * y1); }
if (a < 0) a = -a, x = -x, y = -y;
return a;
}
ll invMod(ll a, ll m) { ll x, y; ll g = extgcd(((a % m) + m) % m, m, x, y); return g != 1 ? -1 : ((x % m) + m) % m; }
ull binaryGcd(ull a, ull b) { // Stein: shifts and subtractions only
if (!a || !b) return a | b;
int s = __builtin_ctzll(a | b); a >>= __builtin_ctzll(a);
while (b) { b >>= __builtin_ctzll(b); if (a > b) swap(a, b); b -= a; }
return a << s;
}
ll lcmSafe(ll a, ll b) { return a / std::gcd(a, b) * b; } // divide first; check against a bound with __int128 if needed| Property | Statement |
|---|---|
| basic divisibility | and and ; and (transitive); and |
| Bézout | : the smallest positive combination is ; is solvable iff |
| every common divisor divides | so is the greatest in the divisibility order |
| coefficient size | the returned $ |
| scaling, coprimality | ; |
| shifting | |
| Euclid’s lemma | prime, or ; |
| products | $\gcd(a, b)\cdot\text{lcm}(a, b) = |
| arrays | (range add keeps the differences) |
| lattice points | the segment – contains lattice points |
| special sequences | ; |
| subarray gcds | the gcds of subarrays ending at take distinct values |
Proof: Euclid, its running time, Bézout and the coefficient bound
Correctness: , so the pairs and have the same common divisors. Time (Lamé): if the algorithm takes steps on , then and by induction (), so ; consecutive Fibonacci numbers attain it. Extended: the loop maintains and (true initially, and preserved because the new remainder is ), so at the end . Bézout: the set is closed under subtraction and integer multiples, so it is for its least positive element ; divides every element, and is a combination equal to by the algorithm, so . Coefficient bound: the cofactor sequences satisfy by the standard continuant argument: the final pair equals , and the absolute values of the cofactors increase monotonically along the run.
Proof: the property table
Euclid’s lemma: if and , then is divisible by . gcd·lcm: by unique factorisation, exponents of and are the minima and maxima of the exponents of , and is the sum. Multiplicativity: with coprime, each prime of divides at most one of them, so the minima split. Arrays: any common divisor of the divides their differences, and conversely a common divisor of and all consecutive differences divides every . Lattice points: points on the segment are with , i.e. for . Fibonacci: gives (consecutive Fibonacci numbers are coprime), which is Euclid’s step on indices. : , again Euclid’s step on exponents. Subarray gcds: along a fixed right end, extending to the left the gcd only changes by dividing it, i.e. by a factor , so there are at most distinct values. Binary gcd: , for odd , ; each round at least halves the larger odd value’s bit length, rounds.
Patterns
vector<pair<ll, ll>> subarrayGcdCounts(const vector<ll>& a) { // {g, number of subarrays with gcd g}
map<ll, ll> total; vector<pair<ll, ll>> cur; // (gcd, count) of subarrays ending at i
for (ll x : a) {
vector<pair<ll, ll>> nxt{{x, 1}};
for (auto [g, c] : cur) { ll h = std::gcd(g, x); if (nxt.back().first == h) nxt.back().second += c; else nxt.push_back({h, c}); }
for (auto [g, c] : nxt) total[g] += c;
cur = move(nxt);
}
return vector<pair<ll, ll>>(all(total));
}
vector<ll> divisorsOf(ll n) { // O(sqrt n), sorted
vector<ll> small, big;
for (ll d = 1; d * d <= n; d++) if (n % d == 0) { small.push_back(d); if (d != n / d) big.push_back(n / d); }
small.insert(small.end(), big.rbegin(), big.rend()); return small;
}| max divisor count | 32 | 240 | 1344 | 6720 | 26880 | 103680 |
for any (sub-polynomial), though is a practical rule of thumb at contest-sized ; the divisor-pair sum drives most sieve-style precomputation (Floor Sums).
- GCD of a range: sparse table (idempotent) in per query after , or a segment tree with point updates.
- Range add + range gcd: keep a segment tree of differences: .
- Counting pairs with : Möbius over multiples (Arithmetic Functions).
- Generalised Euclid / floor sums run the same recursion on (Floor Sums).