All Euler problems
Project Euler

abc-hits

The radical of n, rad(n), is the product of the distinct prime factors of n. A triple (a, b, c) is an abc-hit if: 1. gcd(a, b) = 1 2. a < b 3. a + b = c 4. rad(abc) < c Find sum c for all abc-hits...

Source sync May 21, 2026
Problem #0127
Level Level 05
Solved By 7,293
Languages C++, Python
Answer 18407904
Length 323 words
number_theorylinear_algebrasearch

Problem Statement

This archive keeps the full statement, math, and original media on the page.

The radical of $n$, $\operatorname{rad}(n)$, is the product of distinct prime factors of $n$. For example, $504 = 2^3 \times 3^2 \times 7$, so $\operatorname{rad}(504) = 2 \times 3 \times 7 = 42$.

We shall define the triplet of positive integers $(a, b, c)$ to be an abc-hit if:

  1. $\gcd(a, b) = \gcd(a, c) = \gcd(b, c) = 1$

  2. $a < b$

  3. $a + b = c$

  4. $\operatorname{rad}(abc) < c$

For example, $(5, 27, 32)$ is an abc-hit, because:

  1. $\gcd(5, 27) = \gcd(5, 32) = \gcd(27, 32) = 1$

  2. $5 < 27$

  3. $5 + 27 = 32$

  4. $\operatorname{4320}{4320} = 30 < 32$

It turns out that abc-hits are quite rare and there are only thirty-one abc-hits for $c < 1000$, with $\sum c = 12523$.

Find $\displaystyle \sum c$ for $c < 120000$.

Problem 127: abc-hits

Mathematical Development

Theorem 1 (Pairwise coprimality). If gcd⁡(a,b)=1\gcd(a, b) = 1 and a+b=ca + b = c, then aa, bb, cc are pairwise coprime.

Proof. Suppose a prime pp divides both aa and c=a+bc = a + b. Then p∣(c−a)=bp \mid (c - a) = b, contradicting gcd⁡(a,b)=1\gcd(a, b) = 1. By symmetry (swapping aa and bb), gcd⁡(b,c)=1\gcd(b, c) = 1 as well. □\square

Theorem 2 (Radical factorization for coprime triples). If aa, bb, cc are pairwise coprime, then rad(abc)=rad(a)⋅rad(b)⋅rad(c)\text{rad}(abc) = \text{rad}(a) \cdot \text{rad}(b) \cdot \text{rad}(c).

Proof. Since aa, bb, cc share no common prime factor, the set of primes dividing abcabc is the disjoint union of primes dividing aa, bb, and cc respectively. Therefore ∏p∣abcp=∏p∣ap⋅∏p∣bp⋅∏p∣cp\prod_{p \mid abc} p = \prod_{p \mid a} p \cdot \prod_{p \mid b} p \cdot \prod_{p \mid c} p. □\square

Lemma 1 (Reformulated condition). The abc-hit condition rad(abc)<c\text{rad}(abc) < c is equivalent to rad(a)⋅rad(b)<c/rad(c)\text{rad}(a) \cdot \text{rad}(b) < c / \text{rad}(c).

Proof. By Theorem 2, rad(abc)=rad(a)⋅rad(b)⋅rad(c)\text{rad}(abc) = \text{rad}(a) \cdot \text{rad}(b) \cdot \text{rad}(c). The inequality rad(a)⋅rad(b)⋅rad(c)<c\text{rad}(a) \cdot \text{rad}(b) \cdot \text{rad}(c) < c divides both sides by rad(c)>0\text{rad}(c) > 0. □\square

Lemma 2 (Coprimality via radicals). For positive integers aa and bb, gcd⁡(a,b)=1\gcd(a, b) = 1 if and only if gcd⁡(rad(a),rad(b))=1\gcd(\text{rad}(a), \text{rad}(b)) = 1.

Proof. (⇒)(\Rightarrow): If a prime pp divides both rad(a)\text{rad}(a) and rad(b)\text{rad}(b), then p∣ap \mid a and p∣bp \mid b, contradicting gcd⁡(a,b)=1\gcd(a,b) = 1. (⇐)(\Leftarrow): If p∣gcd⁡(a,b)p \mid \gcd(a,b), then p∣rad(a)p \mid \text{rad}(a) and p∣rad(b)p \mid \text{rad}(b), contradicting gcd⁡(rad(a),rad(b))=1\gcd(\text{rad}(a), \text{rad}(b)) = 1. □\square

Theorem 3 (Search strategy). For each cc, sorting candidates aa by rad(a)\text{rad}(a) in ascending order allows early termination: once rad(a)≥c/rad(c)\text{rad}(a) \geq c / \text{rad}(c), no further aa can satisfy the condition (since rad(b)≥1\text{rad}(b) \geq 1).

Proof. If rad(a)≥c/rad(c)\text{rad}(a) \geq c / \text{rad}(c), then rad(a)⋅rad(b)≥rad(a)≥c/rad(c)\text{rad}(a) \cdot \text{rad}(b) \geq \text{rad}(a) \geq c / \text{rad}(c) for all bb. Thus the condition rad(a)⋅rad(b)<c/rad(c)\text{rad}(a) \cdot \text{rad}(b) < c / \text{rad}(c) fails, and all subsequent aa (with equal or larger radical) also fail. □\square

Editorial

The radical condition is what makes the search manageable. For a fixed cc, Theorem 2 rewrites rad⁡(abc)<c\operatorname{rad}(abc) < c as a bound on rad⁡(a)rad⁡(b)\operatorname{rad}(a)\operatorname{rad}(b), so once rad⁡(c)\operatorname{rad}(c) is known, only values of aa with sufficiently small radical can possibly work. That suggests computing all radicals first and then iterating candidate aa values in increasing radical order.

The implementation follows exactly that plan. It sieves the radical array, sorts the integers by radical, and for each cc scans only as far as the threshold allows. For every surviving aa, it recovers b=c−ab=c-a, enforces a<ba<b, checks the radical inequality, and uses the coprimality test to confirm an abc-hit before adding cc to the total.

Pseudocode

Use a sieve to compute rad(n) for every n below the limit.
Create the list of candidate a-values sorted by increasing rad(a).

For each c from 3 up to 119999:
    Compute the threshold c / rad(c).
    Scan the sorted a-values only while rad(a) stays below that threshold.
    For each such a:
        Set b = c - a.
        Skip the pair unless a < b.
        Skip it unless rad(a) rad(b) is still below the threshold.
        Skip it unless the coprimality condition holds.
        Otherwise record an abc-hit and add c to the answer.

Return the accumulated sum.

Complexity Analysis

  • Time: O(Nlog⁡log⁡N)O(N \log \log N) for the sieve. O(Nlog⁡N)O(N \log N) for sorting. The main search loop: for each cc, the inner loop terminates early due to the radical threshold. Empirically, the total work across all cc is O(Nlog⁡N)O(N \log N).
  • Space: O(N)O(N) for the radical array and sorted index.

Answer

18407904\boxed{18407904}

Code

Each problem page includes the exact C++ and Python source files from the local archive.

C++ project_euler/problem_127/solution.cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
    const int N = 120000;
    vector<int> rad(N, 1);

    // Sieve for radicals
    for (int p = 2; p < N; p++) {
        if (rad[p] == 1) { // p is prime
            for (int m = p; m < N; m += p) {
                rad[m] *= p;
            }
        }
    }

    // Sort indices 1..N-1 by radical (skip 0)
    vector<int> sorted_by_rad;
    sorted_by_rad.reserve(N - 1);
    for (int i = 1; i < N; i++) sorted_by_rad.push_back(i);
    sort(sorted_by_rad.begin(), sorted_by_rad.end(),
         [&](int x, int y) { return rad[x] < rad[y]; });

    long long total = 0;

    for (int c = 3; c < N; c++) {
        long long threshold = (long long)c / rad[c];
        if (threshold <= 1) continue;

        for (int i = 0; i < (int)sorted_by_rad.size(); i++) {
            int a = sorted_by_rad[i];
            if (rad[a] >= threshold) break;
            if (a >= c) continue;
            int b = c - a;
            if (a >= b) continue;
            if ((long long)rad[a] * rad[b] >= threshold) continue;
            if (__gcd(rad[a], rad[b]) != 1) continue;
            total += c;
        }
    }

    cout << total << endl;
    return 0;
}