Open Source · 7 Languages · 900+ Problems

Project Euler Solutions

Complete solutions in C++, Python & Java — with step-by-step mathematical explanations

All Problems

Problem 512: Sums of Totients of Powers

View on Project Euler

Project Euler Problem 512 Solution

EulerSolve provides an optimized solution for Project Euler Problem 512, Sums of Totients of Powers, with C++, Python, Java, and a step-by-step mathematical explanation.

Problem Summary For this problem, the required total can be rewritten as the odd totient prefix sum $G(n)=\sum_{\substack{1\le m\le n\\ m\text{ odd}}}\varphi(m),$ where \(\varphi\) is Euler's totient function. At the target scale \(n=500000000\), directly evaluating every odd \(\varphi(m)\) is too expensive. The implementation therefore replaces the raw summation by a divisor identity, a closed formula for an auxiliary prefix sum, and a memoized divide-and-conquer recurrence. Mathematical Approach We keep the notation $G(n)=\sum_{\substack{1\le m\le n\\ m\text{ odd}}}\varphi(m)$ and define the odd part of a positive integer by $\operatorname{odd}(x)=\frac{x}{2^{v_2(x)}}.$ The auxiliary summatory function used by the implementation is $A(n)=\sum_{x=1}^{n}\operatorname{odd}(x).$ Step 1: Relate Odd Divisors to the Odd Part Every odd divisor of \(x\) is exactly a divisor of \(\operatorname{odd}(x)\). The classical identity $\sum_{d\mid m}\varphi(d)=m$ therefore gives $\sum_{\substack{d\mid x\\ d\text{ odd}}}\varphi(d)=\sum_{d\mid \operatorname{odd}(x)}\varphi(d)=\operatorname{odd}(x).$ This is the key arithmetic fact behind the whole algorithm: instead of summing totients directly, we first sum the odd parts of all integers up to \(n\)....

Detailed mathematical approach

Problem Summary

For this problem, the required total can be rewritten as the odd totient prefix sum

$G(n)=\sum_{\substack{1\le m\le n\\ m\text{ odd}}}\varphi(m),$

where \(\varphi\) is Euler's totient function. At the target scale \(n=500000000\), directly evaluating every odd \(\varphi(m)\) is too expensive. The implementation therefore replaces the raw summation by a divisor identity, a closed formula for an auxiliary prefix sum, and a memoized divide-and-conquer recurrence.

Mathematical Approach

We keep the notation

$G(n)=\sum_{\substack{1\le m\le n\\ m\text{ odd}}}\varphi(m)$

and define the odd part of a positive integer by

$\operatorname{odd}(x)=\frac{x}{2^{v_2(x)}}.$

The auxiliary summatory function used by the implementation is

$A(n)=\sum_{x=1}^{n}\operatorname{odd}(x).$

Step 1: Relate Odd Divisors to the Odd Part

Every odd divisor of \(x\) is exactly a divisor of \(\operatorname{odd}(x)\). The classical identity

$\sum_{d\mid m}\varphi(d)=m$

therefore gives

$\sum_{\substack{d\mid x\\ d\text{ odd}}}\varphi(d)=\sum_{d\mid \operatorname{odd}(x)}\varphi(d)=\operatorname{odd}(x).$

This is the key arithmetic fact behind the whole algorithm: instead of summing totients directly, we first sum the odd parts of all integers up to \(n\).

Step 2: Convert the Divisor Sum into a Summatory Recurrence

Summing the previous identity over \(1\le x\le n\) and exchanging the order of summation yields

$A(n)=\sum_{x=1}^{n}\sum_{\substack{d\mid x\\ d\text{ odd}}}\varphi(d)=\sum_{\substack{d\le n\\ d\text{ odd}}}\varphi(d)\left\lfloor\frac{n}{d}\right\rfloor.$

Now use the standard floor-sum rearrangement

$\sum_{d\le n} a(d)\left\lfloor\frac{n}{d}\right\rfloor=\sum_{t=1}^{n}\sum_{d\le \lfloor n/t\rfloor}a(d).$

With \(a(d)=\varphi(d)\) for odd \(d\) and \(a(d)=0\) for even \(d\), this becomes

$A(n)=\sum_{t=1}^{n}G\left(\left\lfloor\frac{n}{t}\right\rfloor\right).$

The term for \(t=1\) is exactly \(G(n)\), so we isolate it and obtain the recurrence

$G(n)=A(n)-\sum_{t=2}^{n}G\left(\left\lfloor\frac{n}{t}\right\rfloor\right).$

Step 3: Compute \(A(n)\) in Closed Form

Write every positive integer uniquely as \(x=2^j u\) with \(u\) odd. Then \(\operatorname{odd}(x)=u\), so grouping by the exponent \(j\) gives

$A(n)=\sum_{j\ge 0}\ \sum_{\substack{u\le \lfloor n/2^j\rfloor\\ u\text{ odd}}}u.$

If \(r=\left\lfloor\frac{u+1}{2}\right\rfloor\), then the odd numbers up to \(u\) are \(1,3,\dots,2r-1\), and

$1+3+\cdots+(2r-1)=r^2.$

Therefore the inner sum has the closed form

$\sum_{\substack{v\le u\\ v\text{ odd}}}v=\left\lfloor\frac{u+1}{2}\right\rfloor^2,$

and hence

$A(n)=\sum_{j\ge 0}\left(\left\lfloor\frac{\lfloor n/2^j\rfloor+1}{2}\right\rfloor\right)^2.$

Only \(O(\log n)\) terms are present, because \(\lfloor n/2^j\rfloor=0\) once \(2^j>n\).

Step 4: Group Equal Quotients

The recurrence still seems to sum over all \(t\), but the quotient \(\left\lfloor n/t\right\rfloor\) repeats on long intervals. If

$q=\left\lfloor\frac{n}{\ell}\right\rfloor,$

then the same quotient persists for every

$t\in[\ell,r],\qquad r=\left\lfloor\frac{n}{q}\right\rfloor.$

So one whole block contributes

$\sum_{t=\ell}^{r}G\left(\left\lfloor\frac{n}{t}\right\rfloor\right)=(r-\ell+1)\,G(q).$

This reduces the cost of one recursive evaluation from linear in \(n\) to the number of distinct quotients, which is \(O(\sqrt n)\).

Step 5: Memoize the Recurrence

The same quotient values appear again and again inside different blocks, so the recurrence is evaluated only once for each distinct argument. After a value \(G(q)\) has been computed, later requests reuse the cached result instead of recomputing the entire subtree.

This turns the formula above into a practical divide-and-conquer algorithm for very large \(n\).

Worked Example: \(n=10\)

First compute \(A(10)\) from the closed form:

$A(10)=\left\lfloor\frac{10+1}{2}\right\rfloor^2+\left\lfloor\frac{5+1}{2}\right\rfloor^2+\left\lfloor\frac{2+1}{2}\right\rfloor^2+\left\lfloor\frac{1+1}{2}\right\rfloor^2=25+9+1+1=36.$

Now use quotient blocks for \(t\ge 2\):

$\left\lfloor\frac{10}{t}\right\rfloor=5,3,2,2,1,1,1,1,1 \qquad (t=2,\dots,10).$

Hence

$G(10)=36-\bigl(G(5)+G(3)+2G(2)+5G(1)\bigr).$

The smaller values are

$G(1)=1,\qquad G(2)=1,\qquad G(3)=1+\varphi(3)=3,\qquad G(5)=1+\varphi(3)+\varphi(5)=7.$

Therefore

$G(10)=36-(7+3+2+5)=19.$

A direct check agrees:

$\varphi(1)+\varphi(3)+\varphi(5)+\varphi(7)+\varphi(9)=1+2+4+6+6=19.$

How the Code Works

The C++, Python, and Java implementations all follow the same structure. For a requested \(n\), the implementation first computes \(A(n)\) by repeatedly halving the current bound and adding the square of the number of odd integers up to that bound. It then evaluates the recurrence for \(G(n)\) by scanning quotient blocks \([\ell,r]\), recursively requesting the smaller value \(G(q)\), and subtracting \((r-\ell+1)G(q)\) from the running total.

A cache keyed by the argument stores every completed subproblem, so each distinct value is solved only once. The three language versions differ only in surface syntax and data-structure choice; mathematically they implement the same recurrence, the same block decomposition, and the same exact integer arithmetic.

Complexity Analysis

Computing \(A(n)\) costs \(O(\log n)\) time because the argument is halved at each step. A single recursive evaluation on argument \(m\) processes one interval for each distinct quotient \(\lfloor m/t\rfloor\), so that call uses \(O(\sqrt m)\) block iterations. If \(M\) denotes the set of distinct cached arguments generated from the original input, the total running time is

$O\left(\sum_{m\in M}\sqrt{m}\right),$

and the memory usage is \(O(|M|)\). In particular, the top-level quotient list already has only \(O(\sqrt n)\) distinct values, which is why this approach is dramatically faster than summing \(\varphi(m)\) for every odd \(m\le n\).

Footnotes and References

  1. Problem page: https://projecteuler.net/problem=512
  2. Euler's totient function and the divisor identity \(\sum_{d\mid m}\varphi(d)=m\).
  3. The odd part of an integer, \(\operatorname{odd}(x)=x/2^{v_2(x)}\).
  4. Dirichlet-style divisor reordering for summatory functions.
  5. Floor-division block decomposition in recursive arithmetic summation.

Mathematical approach · C++ solution · Python solution · Java solution

Previous: Problem 511 · All Project Euler solutions · Next: Problem 513

Need help with a problem? Ask me! 💡
e
✦ Euler GLM 5.2
Hi! I'm Euler. Ask me anything about Project Euler problems, math concepts, or solution approaches! 🧮