Open Source · 7 Languages · 900+ Problems

Project Euler Solutions

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

All Problems

Problem 428: Necklace of Circles

View on Project Euler

Project Euler Problem 428 Solution

EulerSolve provides an optimized solution for Project Euler Problem 428, Necklace of Circles, with C++, Python, Java, and a step-by-step mathematical explanation.

Problem Summary For each positive integer \(n\), let \(T(n)\) be the number of positive integer triples \((a,b,c)\) with \(b \le n\) that satisfy the necklace condition from the problem statement. The direct geometric search is far too large for \(n=10^9\), so the solution used by the implementations turns the geometry into a divisor-counting problem and then evaluates that arithmetic description with cached summatory functions. Mathematical Approach The three implementations all start from the same arithmetic reduction of the necklace condition. The relevant chain lengths are \(k=3\), \(k=4\), and \(k=6\), leading to the Diophantine families $k=3:\ (a-3b)(c-3b)=12b^2,$ $k=4:\ (a-b)(c-b)=2b^2,$ $k=6:\ (3a-b)(3c-b)=4b^2.$ So the geometric configuration is reduced to counting admissible factorizations of \(2b^2\), \(4b^2\), \(12b^2\), and \(36b^2\), together with the local congruence restrictions forced by the primes \(2\) and \(3\). Step 1: Separate the Squarefree Part Away from \(2\) and \(3\) For primes \(p \ge 5\), only the squarefree divisor pattern matters. Define $u(m)=\sum_{\substack{d \mid m\\ \mu^2(d)=1\\ (d,6)=1}} 1,$ the number of squarefree divisors of \(m\) that are coprime to \(6\)....

Detailed mathematical approach

Problem Summary

For each positive integer \(n\), let \(T(n)\) be the number of positive integer triples \((a,b,c)\) with \(b \le n\) that satisfy the necklace condition from the problem statement. The direct geometric search is far too large for \(n=10^9\), so the solution used by the implementations turns the geometry into a divisor-counting problem and then evaluates that arithmetic description with cached summatory functions.

Mathematical Approach

The three implementations all start from the same arithmetic reduction of the necklace condition. The relevant chain lengths are \(k=3\), \(k=4\), and \(k=6\), leading to the Diophantine families

$k=3:\ (a-3b)(c-3b)=12b^2,$

$k=4:\ (a-b)(c-b)=2b^2,$

$k=6:\ (3a-b)(3c-b)=4b^2.$

So the geometric configuration is reduced to counting admissible factorizations of \(2b^2\), \(4b^2\), \(12b^2\), and \(36b^2\), together with the local congruence restrictions forced by the primes \(2\) and \(3\).

Step 1: Separate the Squarefree Part Away from \(2\) and \(3\)

For primes \(p \ge 5\), only the squarefree divisor pattern matters. Define

$u(m)=\sum_{\substack{d \mid m\\ \mu^2(d)=1\\ (d,6)=1}} 1,$

the number of squarefree divisors of \(m\) that are coprime to \(6\). Its summatory function is

$B(x)=\sum_{m \le x} u(m)=\sum_{\substack{d \le x\\ \mu^2(d)=1\\ (d,6)=1}}\left\lfloor\frac{x}{d}\right\rfloor.$

This function is the basic building block of the whole computation. Intuitively, it captures the contribution of all primes other than \(2\) and \(3\), while the local behavior at those two exceptional primes is handled separately.

Step 2: Count Squarefree Integers Coprime to \(6\)

To evaluate \(B(x)\), the implementations first count squarefree numbers by Möbius inversion:

$Q(x)=\sum_{k \le \sqrt{x}} \mu(k)\left\lfloor\frac{x}{k^2}\right\rfloor.$

Now let \(Q_6(x)\) denote the number of squarefree integers \(\le x\) that are coprime to \(6\). Every squarefree integer can be written uniquely as \(e m\) with \(e \in \{1,2,3,6\}\) and \((m,6)=1\), so

$Q(x)=Q_6(x)+Q_6\left(\left\lfloor\frac{x}{2}\right\rfloor\right)+Q_6\left(\left\lfloor\frac{x}{3}\right\rfloor\right)+Q_6\left(\left\lfloor\frac{x}{6}\right\rfloor\right).$

Rearranging gives the recursion used in the code:

$Q_6(x)=Q(x)-Q_6\left(\left\lfloor\frac{x}{2}\right\rfloor\right)-Q_6\left(\left\lfloor\frac{x}{3}\right\rfloor\right)-Q_6\left(\left\lfloor\frac{x}{6}\right\rfloor\right).$

Once \(Q_6\) is memoized, \(B(x)\) follows from the floor-sum identity above.

Step 3: Local Factors at the Primes \(2\) and \(3\)

After the squarefree part away from \(2\) and \(3\) has been isolated, the remaining arithmetic is encoded in four summatory functions. If \(B\) is the common base term from the previous step, the local combinations used by the implementations are

$P_2(x)=2B(x)+2B\left(\left\lfloor\frac{x}{3}\right\rfloor\right),$

$P_4(x)=3B(x)+3B\left(\left\lfloor\frac{x}{3}\right\rfloor\right)-B\left(\left\lfloor\frac{x}{2}\right\rfloor\right)-B\left(\left\lfloor\frac{x}{6}\right\rfloor\right),$

$P_{12}(x)=6B(x)-2B\left(\left\lfloor\frac{x}{2}\right\rfloor\right),$

$P_{36}(x)=9B(x)-3B\left(\left\lfloor\frac{x}{2}\right\rfloor\right)-3B\left(\left\lfloor\frac{x}{3}\right\rfloor\right)+B\left(\left\lfloor\frac{x}{6}\right\rfloor\right).$

These are the exact linear combinations implemented in C++, Python, and Java. They represent the different local weights coming from the three Diophantine families once the odd squarefree part has been factored out.

Step 4: Turn the Outer Sums into Harmonic Floor Sums

For each \(D \in \{2,4,12,36\}\), write

$P_D(x)=\sum_{m \le x} p_D(m).$

The corresponding outer contribution is then

$M_D(n)=\sum_{m \le n} p_D(m)\left\lfloor\frac{n}{m}\right\rfloor.$

The program does not evaluate this sum term by term. Instead, it groups intervals on which \(\left\lfloor n/m \right\rfloor\) is constant. If \(\left\lfloor n/m \right\rfloor=v\) for all \(m \in [L,R]\), then that whole block contributes

$v\left(P_D(R)-P_D(L-1)\right).$

Because the quotient \(\left\lfloor n/m \right\rfloor\) takes only \(O(\sqrt{n})\) distinct values, this reduces a linear scan to a near square-root computation.

Step 5: The Modulo-\(3\) Character Correction

The case \(3 \nmid b\) needs one extra correction term. Introduce the nontrivial Dirichlet character modulo \(3\):

$\chi(m)=\begin{cases} 1,&m\equiv 1\pmod 3,\\ -1,&m\equiv 2\pmod 3,\\ 0,&3\mid m. \end{cases}$

For squarefree numbers, the weighted prefix sum

$R(x)=\sum_{\substack{m \le x\\ \mu^2(m)=1}}\chi(m)$

is again computed by Möbius inversion:

$R(x)=\sum_{\substack{k \le \sqrt{x}\\ 3 \nmid k}} \mu(k)\sum_{t \le x/k^2}\chi(t).$

The inner character sum is especially simple, because

$\sum_{t \le y}\chi(t)=\begin{cases} 1,&y\equiv 1\pmod 3,\\ 0,&y\equiv 0,2\pmod 3. \end{cases}$

Now define the divisor-weighted function

$c(m)=\sum_{d \mid m}\mu^2(d)\chi(d).$

Since \(\chi(d)=0\) whenever \(3 \mid d\), we have \(c(3m)=c(m)\). Therefore the summatory function restricted to \(3 \nmid m\) is obtained by subtraction, and the final correction term has the form

$H(n)=\sum_{\substack{m \le n\\ \left\lfloor n/m \right\rfloor \equiv 1 \pmod 3}} c(m)\,\mathbf{1}_{3 \nmid m}.$

This is exactly the extra term that appears in the \(3 \nmid b\) branch of the implementation.

Step 6: Final Assembly by the \(3\)-Adic Valuation of \(b\)

The total is split according to the power of \(3\) dividing \(b\). For the case \(3 \nmid b\), the contribution is

$C_0(n)=\frac{M_4(n)-M_{36}\left(\left\lfloor\frac{n}{3}\right\rfloor\right)-H(n)}{2}.$

If \(v_3(b)=t \ge 1\), the local multiplicity becomes \(2t-1\), so the higher \(3\)-adic layers contribute

$C_{\ge 1}(n)=\sum_{t \ge 1}(2t-1)\left(M_4\left(\left\lfloor\frac{n}{3^t}\right\rfloor\right)-M_{36}\left(\left\lfloor\frac{n}{3^{t+1}}\right\rfloor\right)\right).$

Putting everything together gives the exact formula implemented by the program:

$\boxed{T(n)=M_2(n)+M_{12}(n)+C_0(n)+C_{\ge 1}(n).}$

How the Code Works

The C++, Python, and Java implementations follow the same pipeline. They precompute Möbius values up to \(\lfloor\sqrt{n}\rfloor\), memoize the count of squarefree integers coprime to \(6\), build the four local summatory functions above, evaluate each outer divisor sum through floor-division blocks, and then add the character correction together with the \(3\)-adic layers. As a sanity check, the arithmetic is verified on small checkpoints such as \(T(1)=9\), \(T(20)=732\), and \(T(3000)=438106\) before the full target is evaluated.

Complexity Analysis

The Möbius sieve up to \(\lfloor\sqrt{n}\rfloor\) costs \(O(\sqrt{n})\) time and memory. Every cached summatory function is queried only at values of the form \(\left\lfloor n/k \right\rfloor\), and there are only \(O(\sqrt{n})\) distinct quotients. In practice the running time is dominated by a small number of harmonic block sums plus memoized recursive lookups, which is fast enough for \(n=10^9\).

Footnotes and References

  1. Problem page: https://projecteuler.net/problem=428
  2. Möbius function: Wikipedia - Möbius function
  3. Squarefree integer: Wikipedia - Squarefree integer
  4. Dirichlet character: Wikipedia - Dirichlet character
  5. Dirichlet hyperbola method: Wikipedia - Dirichlet hyperbola method

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

Previous: Problem 427 · All Project Euler solutions · Next: Problem 429

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! 🧮