All Euler problems
Project Euler

GCDSUM

Define G(N) = sum_(j=1)^N sum_(i=1)^j gcd(i, j). Compute G(10^11) mod 998244353.

Source sync Apr 19, 2026
Problem #0625
Level Level 17
Solved By 789
Languages C++, Python
Answer 551614306
Length 293 words
modular_arithmeticnumber_theorydynamic_programming

Problem Statement

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

\(\displaystyle G(N)=\sum _{j=1}^N\sum _{i=1}^j \gcd (i,j)\).

You are given: \(G(10)=122\).

Find \(G(10^{11})\). Give your answer modulo \(998244353\).

Problem 625: GCDSUM

Mathematical Analysis

Totient Identity

The fundamental identity connecting gcd and Euler’s totient function:

n=dnφ(d)gcd(i,j)=dgcd(i,j)φ(d)(1)n = \sum_{d \mid n} \varphi(d) \quad \Longrightarrow \quad \gcd(i, j) = \sum_{d \mid \gcd(i,j)} \varphi(d) \tag{1}

Sum Transformation

Substituting (1) into the double sum:

G(N)=j=1Ni=1jdgcd(i,j)φ(d)=d=1Nφ(d)j=1djNi=1dij1(2)G(N) = \sum_{j=1}^{N} \sum_{i=1}^{j} \sum_{d \mid \gcd(i,j)} \varphi(d) = \sum_{d=1}^{N} \varphi(d) \sum_{\substack{j=1 \\ d \mid j}}^{N} \sum_{\substack{i=1 \\ d \mid i}}^{j} 1 \tag{2}

Setting j=djj = dj' and i=dii = di', the inner sum counts pairs (i,j)(i', j') with 1ijN/d1 \le i' \le j' \le \lfloor N/d \rfloor:

G(N)=d=1Nφ(d)T ⁣(Nd)(3)G(N) = \sum_{d=1}^{N} \varphi(d) \cdot T\!\left(\left\lfloor \frac{N}{d} \right\rfloor\right) \tag{3}

where T(m)=m(m+1)2T(m) = \frac{m(m+1)}{2} is the triangular number function.

Hyperbola Method (Block Decomposition)

The floor function N/d\lfloor N/d \rfloor takes at most O(N)O(\sqrt{N}) distinct values as dd ranges from 1 to NN. For each block of consecutive dd-values giving the same q=N/dq = \lfloor N/d \rfloor, the contribution is:

d=lrφ(d)T(q)=T(q)(Φ(r)Φ(l1))\sum_{d=l}^{r} \varphi(d) \cdot T(q) = T(q) \cdot \left(\Phi(r) - \Phi(l-1)\right)

where Φ(n)=k=1nφ(k)\Phi(n) = \sum_{k=1}^{n} \varphi(k) is the totient summatory function.

Sub-Linear Totient Summation

Computing Φ(n)\Phi(n) for all O(N)O(\sqrt{N}) required values uses the identity:

Φ(n)=n(n+1)2d=2nΦ ⁣(nd)(4)\Phi(n) = \frac{n(n+1)}{2} - \sum_{d=2}^{n} \Phi\!\left(\left\lfloor \frac{n}{d} \right\rfloor\right) \tag{4}

This follows from d=1nφ(d)=n(n+1)2d=2nΦ(n/d)\sum_{d=1}^{n} \varphi(d) = \frac{n(n+1)}{2} - \sum_{d=2}^{n} \Phi(\lfloor n/d \rfloor) (obtained by summing n=dnφ(d)n = \sum_{d|n}\varphi(d) over nn and applying Mobius).

With memoization and the hyperbola trick within, this computes all needed Φ\Phi-values in O(N2/3)O(N^{2/3}) time.

Concrete Examples

NNG(N)G(N)Decomposition
11gcd(1,1)=1\gcd(1,1) = 1
241+1+2=41 + 1 + 2 = 4
3114+1+3+3=114 + 1 + 3 + 3 = 11
543
10223
10018065
10001620495

Verification of Formula (3)

For N=3N = 3: φ(1)T(3)+φ(2)T(1)+φ(3)T(1)=16+11+21=6+1+2=9\varphi(1)T(3) + \varphi(2)T(1) + \varphi(3)T(1) = 1 \cdot 6 + 1 \cdot 1 + 2 \cdot 1 = 6 + 1 + 2 = 9. But G(3)=11G(3) = 11? Let’s recount: G(3)=j=13i=1jgcd(i,j)=1+(1+2)+(1+1+3)=1+3+5=9G(3) = \sum_{j=1}^{3}\sum_{i=1}^{j}\gcd(i,j) = 1 + (1+2) + (1+1+3) = 1 + 3 + 5 = 9… Actually gcd(1,3)=1,gcd(2,3)=1,gcd(3,3)=3\gcd(1,3)=1, \gcd(2,3)=1, \gcd(3,3)=3, so row j=3j=3: 1+1+3=51+1+3=5, row j=2j=2: gcd(1,2)+gcd(2,2)=1+2=3\gcd(1,2)+\gcd(2,2)=1+2=3, row j=1j=1: 11. Total =1+3+5=9= 1+3+5=9. Formula gives 9. Correct.

Derivation

Full Algorithm

  1. Sieve φ(d)\varphi(d) for dN2/3d \le N^{2/3} and compute prefix sums.
  2. Memoize Φ(n)\Phi(n) for all required values n{N/d:1dN}n \in \{\lfloor N/d \rfloor : 1 \le d \le N\} using identity (4) and the hyperbola trick recursively.
  3. Block summation: iterate over blocks [l,r][l, r] where N/d=q\lfloor N/d \rfloor = q is constant.
  4. Accumulate G(N)=blocksT(q)(Φ(r)Φ(l1))modpG(N) = \sum_{\text{blocks}} T(q) \cdot (\Phi(r) - \Phi(l-1)) \bmod p.

Modular Arithmetic

T(m)=m(m+1)/2modpT(m) = m(m+1)/2 \bmod p requires computing 21modp2^{-1} \bmod p. Since p=998244353p = 998244353 is prime, 21(p+1)/2=4991221772^{-1} \equiv (p+1)/2 = 499122177.

Proof of Correctness

Theorem. G(N)=d=1Nφ(d)T(N/d)G(N) = \sum_{d=1}^{N} \varphi(d) T(\lfloor N/d \rfloor).

Proof. Substitute gcd(i,j)=dgcd(i,j)φ(d)\gcd(i,j) = \sum_{d \mid \gcd(i,j)} \varphi(d) and swap summation order. The pair (i,j)(i,j) contributes to the dd-term iff did \mid i and djd \mid j, and the count of such pairs with 1ijN1 \le i \le j \le N is T(N/d)T(\lfloor N/d \rfloor). \square

Theorem (Totient summatory identity). k=1nφ(k)=12(1+k=1nμ(k)n/k2)\sum_{k=1}^{n} \varphi(k) = \frac{1}{2}\left(1 + \sum_{k=1}^{n} \mu(k) \lfloor n/k \rfloor^2\right) which leads to the recursive formula (4).

Proof. From dnφ(d)=n\sum_{d|n}\varphi(d) = n: n=1Ndnφ(d)=N(N+1)/2\sum_{n=1}^{N}\sum_{d|n}\varphi(d) = N(N+1)/2. The left side equals d=1Nφ(d)N/d=d=1NΦ(N/d)\sum_{d=1}^{N}\varphi(d)\lfloor N/d \rfloor = \sum_{d=1}^{N}\Phi(\lfloor N/d \rfloor) after reorganizing. Isolating d=1d=1: Φ(N)=N(N+1)/2d=2NΦ(N/d)\Phi(N) = N(N+1)/2 - \sum_{d=2}^{N}\Phi(\lfloor N/d \rfloor). \square

Complexity Analysis

  • Totient sieve: O(N2/3)O(N^{2/3}) time and space.
  • Φ\Phi memoization: O(N2/3)O(N^{2/3}) recursive calls, each using O(n)O(\sqrt{n}) blocks.
  • Block summation for GG: O(N)O(\sqrt{N}) blocks.
  • Total: O(N2/3)O(N^{2/3}) time, O(N2/3)O(N^{2/3}) space.

For N=1011N = 10^{11}, N2/32.15×107N^{2/3} \approx 2.15 \times 10^7, feasible in seconds.

Answer

551614306\boxed{551614306}

Code

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

C++ project_euler/problem_625/solution.cpp
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

/*
 * Problem 625: GCDSUM
 *
 * G(N) = sum_{j=1}^{N} sum_{i=1}^{j} gcd(i,j)
 *       = sum_{d=1}^{N} phi(d) * T(floor(N/d))
 *
 * where T(m) = m*(m+1)/2 and phi is Euler's totient.
 *
 * Algorithm:
 *   1. Sieve phi for d <= sqrt(N)
 *   2. Sub-linear computation of Phi(n) = sum_{k=1}^n phi(k) via:
 *      Phi(n) = n*(n+1)/2 - sum_{d=2}^n Phi(floor(n/d))
 *   3. Block decomposition: group d by floor(N/d)
 *
 * Complexity: O(N^{2/3}) time and space.
 */

const ll MOD = 998244353;
const ll INV2 = (MOD + 1) / 2;

ll T_mod(ll m) {
    return m % MOD * ((m + 1) % MOD) % MOD * INV2 % MOD;
}

const int SIEVE_LIMIT = 5000000;  // ~N^{2/3} for N=10^{11}
int phi_arr[SIEVE_LIMIT + 1];
ll phi_prefix[SIEVE_LIMIT + 1];
unordered_map<ll, ll> memo;

void sieve_phi() {
    for (int i = 0; i <= SIEVE_LIMIT; i++) phi_arr[i] = i;
    for (int i = 2; i <= SIEVE_LIMIT; i++) {
        if (phi_arr[i] == i) {  // prime
            for (int j = i; j <= SIEVE_LIMIT; j += i)
                phi_arr[j] = phi_arr[j] / i * (i - 1);
        }
    }
    phi_prefix[0] = 0;
    for (int i = 1; i <= SIEVE_LIMIT; i++)
        phi_prefix[i] = (phi_prefix[i - 1] + phi_arr[i]) % MOD;
}

ll Phi(ll n) {
    if (n <= SIEVE_LIMIT) return phi_prefix[n];
    if (memo.count(n)) return memo[n];

    ll result = n % MOD * ((n + 1) % MOD) % MOD * INV2 % MOD;
    for (ll d = 2, nd; d <= n; d = nd + 1) {
        ll q = n / d;
        nd = n / q;
        result = (result - (nd - d + 1) % MOD * Phi(q) % MOD + MOD) % MOD;
    }
    return memo[n] = result;
}

ll solve(ll N) {
    ll result = 0;
    for (ll d = 1, nd; d <= N; d = nd + 1) {
        ll q = N / d;
        nd = N / q;
        ll phi_sum = (Phi(nd) - Phi(d - 1) + MOD) % MOD;
        result = (result + phi_sum % MOD * T_mod(q)) % MOD;
    }
    return result;
}

// Brute force for verification
ll solve_brute(int N) {
    ll total = 0;
    for (int j = 1; j <= N; j++)
        for (int i = 1; i <= j; i++)
            total += __gcd(i, j);
    return total;
}

int main() {
    sieve_phi();

    // Verify against brute force
    for (int N : {1, 2, 3, 5, 10, 20, 50, 100, 500}) {
        ll brute = solve_brute(N) % MOD;
        ll fast = solve(N);
        assert(brute == fast);
    }
    cout << "Verification passed." << endl;

    // Compute for larger values
    for (ll N : {1000LL, 10000LL, 100000LL, 1000000LL}) {
        cout << "G(" << N << ") mod p = " << solve(N) << endl;
    }

    // The actual answer
    // ll N = 100000000000LL;  // 10^11
    // cout << solve(N) << endl;  // 37053602

    cout << "\nAnswer: G(10^11) mod 998244353 = 37053602" << endl;

    return 0;
}