GCD and LCM: the small things I wish I knew earlier

Revision en1, by ChallaAjay, 2026-10-20 05:29:45

Hi everyone!

I'm not a high-rated guy (just ~1300), so this isn't some deep post. I just noticed that gcd and lcm show up in a LOT of problems, and every time I would forget some tiny detail and lose time on it. So I wrote everything in one place. Maybe it helps someone who is at the same stage as me, and if I got something wrong please tell me in the comments, I'll fix it :)

1. Euclid's algorithm

The whole idea is one line:

Unable to parse markup [type=CF_MATHJAX]

$, and when

Unable to parse markup [type=CF_MATHJAX]

$ the answer is

Unable to parse markup [type=CF_MATHJAX]

$.

long long gcd(long long a, long long b) {
    while (b) {
        a %= b;
        swap(a, b);
    }
    return a;
}

If you use C++17 you can just write std::gcd(a, b) (it's in <numeric>). On older compilers __gcd(a, b) works too.

It runs in

Unable to parse markup [type=CF_MATHJAX]

$. Reason: every two steps the bigger number becomes at least half of what it was. So even for

Unable to parse markup [type=CF_MATHJAX]

$ it's like 90 steps, nothing to worry about.

One small thing:

Unable to parse markup [type=CF_MATHJAX]

$. This is useful because you can start the gcd of an array from 0 and not worry about the first element.

2. LCM (and the overflow trap)

Unable to parse markup [type=CF_MATHJAX]

$

Please divide first, then multiply. If you do a * b / gcd(a, b), the product can overflow even when the final answer would fit. With

Unable to parse markup [type=CF_MATHJAX]

$ the lcm can be up to

Unable to parse markup [type=CF_MATHJAX]

$, which fits in long long but definitely not in int.

long long lcm(long long a, long long b) {
    return a / gcd(a, b) * b;
}

Also remember

Unable to parse markup [type=CF_MATHJAX]

$. It's handy more often than you'd think.

3. GCD of an array

long long g = 0;
for (long long x : a) g = gcd(g, x);

A trick that appears a lot: "what is the gcd if I remove one element?" For this, build prefix and suffix gcd arrays:

// pre[i] = gcd(a[0..i]),  suf[i] = gcd(a[i..n-1])
// gcd without a[i] = gcd(pre[i-1], suf[i+1])

(be careful with the borders, i = 0 and i = n-1. This is where I usually get WA.)

4. Some properties worth remembering

Unable to parse markup [type=CF_MATHJAX]

$, so

Unable to parse markup [type=CF_MATHJAX]

$ always divides

Unable to parse markup [type=CF_MATHJAX]

$. -

Unable to parse markup [type=CF_MATHJAX]

$ divides

Unable to parse markup [type=CF_MATHJAX]

$ for any

Unable to parse markup [type=CF_MATHJAX]

$. This helps in problems where you add the same number to two values and want them to share a factor. - If

Unable to parse markup [type=CF_MATHJAX]

$, you can write

Unable to parse markup [type=CF_MATHJAX]

$,

Unable to parse markup [type=CF_MATHJAX]

$ with

Unable to parse markup [type=CF_MATHJAX]

$. A lot of problems become much easier after this substitution. - While you go through an array, the prefix gcd changes at most

Unable to parse markup [type=CF_MATHJAX]

$ times, since every time it changes it becomes at most half of the previous value.

5. Extended Euclid

It finds

Unable to parse markup [type=CF_MATHJAX]

$ such that

Unable to parse markup [type=CF_MATHJAX]

$.

long long exgcd(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1; y = 0;
        return a;
    }
    long long x1, y1;
    long long g = exgcd(b, a % b, x1, y1);
    x = y1;
    y = x1 - (a / b) * y1;
    return g;
}

Where it's useful: - The equation

Unable to parse markup [type=CF_MATHJAX]

$ has an integer solution if and only if

Unable to parse markup [type=CF_MATHJAX]

$ divides

Unable to parse markup [type=CF_MATHJAX]

$. - Modular inverse of

Unable to parse markup [type=CF_MATHJAX]

$ modulo

Unable to parse markup [type=CF_MATHJAX]

$ when

Unable to parse markup [type=CF_MATHJAX]

$: run exgcd(a, m, x, y) and take

Unable to parse markup [type=CF_MATHJAX]

$ modulo

Unable to parse markup [type=CF_MATHJAX]

$ (make it positive!). This works even when

Unable to parse markup [type=CF_MATHJAX]

$ is not prime, unlike Fermat's trick.

6. Mistakes I (and probably you) make

  • Using int for lcm and getting overflow.
  • Multiplying before dividing.
  • Forgetting that

Unable to parse markup [type=CF_MATHJAX]

$, and then dividing by it. - Forgetting that the lcm of a whole array grows really fast, so it may not fit in long long after a few elements.

7. Problems to practice

Easy ones to start with: - 1325A - EhAb AnD gCd EhAb AnD gCd - 1498A - GCD Sum GCD Sum

After that, go to the problemset, filter by the tag "number theory" and rating 800 to 1500, and solve a few. I'm still doing this myself.

That's all, thanks for reading!

Question for you: what is the most interesting or surprising problem you have seen that uses gcd? I would like to add it to the list. Also if you know a nicer way to explain any part here, please share.

Tags gcd, lcm, euclidean algorithm, advice

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
en2 English ChallaAjay 2026-10-20 05:31:29 494
en1 English ChallaAjay 2026-10-20 05:29:45 4332 Initial revision (published)