Open Source · 7 Languages · 900+ Problems

Project Euler Solutions

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

All Problems

Problem 935: Rolling Square

View on Project Euler

Project Euler Problem 935 Solution

EulerSolve provides an optimized solution for Project Euler Problem 935, Rolling Square, with C++, Python, Java, and a step-by-step mathematical explanation.

Problem Summary The implementations do not simulate a square rolling step by step. Instead, they use a number-theoretic parametrization in which each admissible contribution is represented by an integer \(q \ge 1\), one of four companion values \(k \in \{4q+1,4q+2,4q+3,4q+4\}\), and a second parameter \(m\) with \(1 \le m \le q\). The key invariant is primitiveness: a contribution is valid exactly when \(\gcd(m,k)=1\). The bound in the problem is imposed through the associated size parameter \(n\): the families \(k=4q+1\), \(4q+2\), and \(4q+4\) contribute at \(n=4q\), while \(k=4q+3\) contributes at \(n=4q+2\). So the total answer up to \(N\) is a cumulative sum over even \(n\), with no odd case at all. Mathematical Approach Once the rolling-square geometry has been reduced to this parametrization, the problem becomes a clean coprime-counting question. The whole job is to evaluate the right coprime counts quickly and add them in the right four families....

Detailed mathematical approach

Problem Summary

The implementations do not simulate a square rolling step by step. Instead, they use a number-theoretic parametrization in which each admissible contribution is represented by an integer \(q \ge 1\), one of four companion values \(k \in \{4q+1,4q+2,4q+3,4q+4\}\), and a second parameter \(m\) with \(1 \le m \le q\).

The key invariant is primitiveness: a contribution is valid exactly when \(\gcd(m,k)=1\). The bound in the problem is imposed through the associated size parameter \(n\): the families \(k=4q+1\), \(4q+2\), and \(4q+4\) contribute at \(n=4q\), while \(k=4q+3\) contributes at \(n=4q+2\). So the total answer up to \(N\) is a cumulative sum over even \(n\), with no odd case at all.

Mathematical Approach

Once the rolling-square geometry has been reduced to this parametrization, the problem becomes a clean coprime-counting question. The whole job is to evaluate the right coprime counts quickly and add them in the right four families.

The Four Admissible Families

Define

$R(q,k)=\#\{1 \le m \le q : \gcd(m,k)=1\}.$

The arithmetic structure visible in the implementations is then

$S(N)=\sum_{q=1}^{\lfloor N/4 \rfloor}\Bigl(R(q,4q+1)+R(q,4q+2)+R(q,4q+4)\Bigr)+\sum_{q=1}^{\lfloor (N-2)/4 \rfloor}R(q,4q+3).$

Equivalently, if \(F(n)\) denotes the contribution attached to one value of \(n\), then

$F(4q)=R(q,4q+1)+R(q,4q+2)+R(q,4q+4), \qquad F(4q+2)=R(q,4q+3),$

and \(F(n)=0\) for odd \(n\). That is the first important invariant: only the residue classes \(0\) and \(2\) modulo 4 can occur.

Primitiveness Becomes a Coprime Count

For fixed \(q\) and \(k\), the only thing that matters about \(m\) is whether it shares a prime factor with \(k\). Prime powers do not create new exclusions: if a prime \(p\) divides \(k\), then every multiple of \(p\) must be removed, regardless of whether \(p\) occurs once or many times in \(k\).

That is why the count depends only on the distinct prime divisors of \(k\). Writing

$\operatorname{rad}(k)=\prod_{p \mid k} p,$

the forbidden values of \(m\) are exactly the multiples of the primes dividing \(\operatorname{rad}(k)\).

Inclusion-Exclusion Over the Distinct Prime Factors

Counting the complement of those forbidden multiples gives the exact formula

$R(q,k)=\sum_{d \mid \operatorname{rad}(k)} \mu(d)\left\lfloor \frac{q}{d}\right\rfloor,$

where \(\mu\) is the Möbius function. This is simply inclusion-exclusion written compactly: start with all \(q\) candidates, subtract multiples of each prime divisor of \(k\), add back multiples of each product of two distinct prime divisors, and continue alternating.

The implementations do not build a global Möbius table. They factor \(k\), list its distinct prime divisors, enumerate all subsets of that list, multiply the chosen primes to obtain \(d\), and add or subtract \(\left\lfloor q/d \right\rfloor\) according to the subset parity. That direct subset view matches the formula exactly.

Worked Example

Take \(q=2\). Then the three \(n=4q=8\) branches are \(k=9\), \(10\), and \(12\).

For \(k=12\), the distinct prime divisors are \(2\) and \(3\), so

$R(2,12)=\left\lfloor\frac{2}{1}\right\rfloor-\left\lfloor\frac{2}{2}\right\rfloor-\left\lfloor\frac{2}{3}\right\rfloor+\left\lfloor\frac{2}{6}\right\rfloor=2-1-0+0=1.$

Also, \(R(2,9)=2\) because both \(1\) and \(2\) are coprime to \(9\), and \(R(2,10)=1\) because only \(1\) is coprime to \(10\). Hence

$F(8)=R(2,9)+R(2,10)+R(2,12)=2+1+1=4.$

The \(4q+2\) branch gives \(n=10\) with \(k=11\), so

$F(10)=R(2,11)=2.$

At the smallest nontrivial level, \(q=1\) gives \(F(4)=3\) and \(F(6)=1\), so \(S(6)=4\), exactly matching the checkpoint embedded in the implementations.

How the Code Works

The C++, Python, and Java implementations all evaluate the same arithmetic decomposition. They differ only in execution strategy, not in the mathematics.

Prime-Factor Preprocessing

A smallest-prime-factor table is precomputed up to \(N+4\). This is a linear sieve, so every later factorization of a candidate \(k\) can peel off its distinct prime divisors in near-constant amortized time per divisor instead of testing divisibility up to \(\sqrt{k}\).

Counting One Branch

For each required value of \(k\), the implementation extracts the distinct prime divisors, enumerates all subset products, and evaluates the inclusion-exclusion sum for \(R(q,k)\). Because the bound is \(m \le q\), each subset contributes exactly one floor term \(\left\lfloor q/d \right\rfloor\).

No symbolic simplification is required. The same routine works uniformly for \(4q+1\), \(4q+2\), \(4q+3\), and \(4q+4\).

Outer Accumulation

The outer loop runs over \(q\) and evaluates the four admissible families, adding a branch only when its associated \(n\) is at most the requested bound. The native implementations split the \(q\)-interval into chunks, let each worker accumulate an exact local sum, and then reduce the partial sums at the end. The Python entry point delegates to the same compiled arithmetic, so it produces the same count rather than a different algorithm.

Complexity Analysis

Let \(K=N+4\) and \(Q=\lfloor K/4 \rfloor\). The sieve phase is \(O(K)\) time and \(O(K)\) memory. That memory cost is the dominant storage use, because the smallest-prime-factor table has one entry per integer up to the limit.

The accumulation phase evaluates up to four candidate values of \(k\) for each \(q\). A single coprime count costs \(O(2^{\omega(k)})\), where \(\omega(k)\) is the number of distinct prime divisors of \(k\). For the target limit \(N=10^8\), every \(k \le 100000004\) has at most 8 distinct prime divisors, so each inclusion-exclusion pass uses at most \(2^8=256\) subset terms. In practice this makes the arithmetic phase very close to linear in the number of processed branches, and parallel chunking improves wall-clock time without changing the exact count.

Footnotes and References

  1. Problem page: Project Euler 935
  2. Inclusion-exclusion principle: Wikipedia - Inclusion-exclusion principle
  3. Möbius function: Wikipedia - Möbius function
  4. Coprime integers: Wikipedia - Coprime integers
  5. Sieve of Eratosthenes and prime preprocessing: Wikipedia - Sieve of Eratosthenes

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

Previous: Problem 934 · All Project Euler solutions · Next: Problem 936

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