All Euler problems
Project Euler

Digital Root Clocks

Sam and Max have digital clocks with 7-segment displays. Starting from a number, they repeatedly compute the digit sum until a single digit remains (the digital root chain). Sam's clock turns off a...

Source sync Apr 19, 2026
Problem #0315
Level Level 07
Solved By 3,837
Languages C++, Python
Answer 13625242
Length 465 words
modular_arithmeticnumber_theorybrute_force

Problem Statement

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

Problem animation

Sam and Max are asked to transform two digital clocks into two "digital root" clocks.

A digital root clock is a digital clock that calculates digital roots step by step.

When a clock is fed a number, it will show it and then it will start the calculation, showing all the intermediate values until it gets to the result.

For example, if the clock is fed the number "137", it will show: "137" $\rightarrow$ "11" $\rightarrow$ "2" and then it will go black, waiting for the next number.

Every digital number consists of some light segments: three horizontal (top, middle, bottom) and four vertical (top-left, top-right, bottom-left, bottom-right).

Number "1" is made of vertical top-right and bottom-right, number "4" is made by middle horizontal and vertical top-left, top-right and bottom-right. Number "8" lights them all.

The clocks consume energy only when segments are turned on/off.

To turn on a "2" will cost $5$ transitions, while a "7" will cost only $4$ transitions.

Sam and Max built two different clocks.

Sam's clock is fed e.g. number $137$: the clock shows "137", then the panel is turned off, then the next number ("11") is turned on, then the panel is turned off again and finally the last number ("2") is turned on and, after some time, off.

For the example, with number $137$, Sam's clock requires:

Sam's Clock Transitions

NumberTransitions
"137"
$(2 + 5 + 4) \times 2$ = 22 transitions ("137" on/off).
"11"
$(2 + 2) \times 2 = 8$ transitions ("11" on/off).
"2"
$(5) \times 2 = 10$ transitions ("2" on/off).

For a grand total of $40$ transitions.

Max's clock works differently. Instead of turning off the whole panel, it is smart enough to turn off only those segments that won't be needed for the next number.

For number $137$, Max's clock requires:

Max's Clock Transitions

NumberTransitions
"137"
$2 + 5 + 4 = 11$ transitions ("137" on).
$7$ transitions (to turn off the segments that are not needed for number "11").
"11"
$0$ transitions (number "11" is already turned on correctly).
$3$ transitions (to turn off the first "1" and the bottom part of the second "1";
the top part is common with number "2").
"2"
$4$ transitions (to turn on the remaining segments in order to get "2").
$5$ transitions (to turn off number "2").

For a grand total of $30$ transitions.

Of course, Max's clock consumes less power than Sam's one.

The two clocks are fed all the prime numbers between $A = 10^7$ and $B = 2\times10^7$.

Find the difference between the total number of transitions needed by Sam's clock and that needed by Max's one.

Problem 315: Digital Root Clocks

Mathematical Foundation

Definition (Segment Encoding). Each decimal digit is represented by a 7-bit mask over segments {a,b,c,d,e,f,g}\{a, b, c, d, e, f, g\}:

DigitSegmentsCountBitmask
0a,b,c,d,e,f60x3F
1b,c20x06
2a,b,d,e,g50x5B
3a,b,c,d,g50x4F
4b,c,f,g40x66
5a,c,d,f,g50x6D
6a,c,d,e,f,g60x7D
7a,b,c,f40x27
8a,b,c,d,e,f,g70x7F
9a,b,c,d,f,g60x6F

Note: digit 7 uses 4 segments (including the top-left vertical ff), per the Project Euler specification.

Definition (Segment Count Functions). For a number nn with digits d1d2dkd_1 d_2 \cdots d_k, define:

  • seg(n)=i=1kM(di)\text{seg}(n) = \sum_{i=1}^{k} |M(d_i)|, the total number of active segments,
  • M(d)M(d) = bitmask of digit dd.

Lemma 1 (Sam’s Cost). For the digital root chain n0,n1,,nKn_0, n_1, \ldots, n_K (where n0=pn_0 = p, nKn_K is a single digit), Sam’s total segment transitions are:

Sam(p)=2i=0Kseg(ni).\text{Sam}(p) = 2 \sum_{i=0}^{K} \text{seg}(n_i).

Proof. Sam turns on all segments of nin_i (cost seg(ni)\text{seg}(n_i)), then turns them all off (cost seg(ni)\text{seg}(n_i)), for each i=0,1,,Ki = 0, 1, \ldots, K. Total: 2iseg(ni)2\sum_i \text{seg}(n_i). \square

Lemma 2 (Max’s Cost). Max’s total segment transitions are:

Max(p)=seg(n0)+i=0K1ham(ni,ni+1)+seg(nK),\text{Max}(p) = \text{seg}(n_0) + \sum_{i=0}^{K-1} \text{ham}(n_i, n_{i+1}) + \text{seg}(n_K),

where ham(ni,ni+1)\text{ham}(n_i, n_{i+1}) is the number of segments that differ between the right-aligned digit-by-digit bitmask representations of nin_i and ni+1n_{i+1} (the Hamming distance of the composite bitmasks, padding shorter numbers with zero on the left).

Proof. Max initially turns on n0n_0 from blank (cost seg(n0)\text{seg}(n_0)). At each transition nini+1n_i \to n_{i+1}, Max toggles only the differing segments (cost ham(ni,ni+1)\text{ham}(n_i, n_{i+1})). Finally, Max turns off nKn_K to blank (cost seg(nK)\text{seg}(n_K)). \square

Theorem (Difference Identity). For any two bitmasks AA and BB:

A+B=AB+2AB|A| + |B| = |A \oplus B| + 2|A \wedge B|

where \oplus is XOR (symmetric difference) and \wedge is AND (intersection). Consequently:

Sam(p)Max(p)=2i=0K1common(ni,ni+1)\text{Sam}(p) - \text{Max}(p) = 2 \sum_{i=0}^{K-1} \text{common}(n_i, n_{i+1})

where common(ni,ni+1)\text{common}(n_i, n_{i+1}) is the number of segments shared between consecutive displays (computed digit-by-digit, right-aligned).

Proof. For bitmasks A,B{0,1}7A, B \subseteq \{0,1\}^7: every bit is either in ABA \cap B, in ABA \setminus B, or in BAB \setminus A. The XOR counts bits in exactly one of A,BA, B; the AND counts bits in both. So A+B=AB+2AB|A| + |B| = |A \oplus B| + 2|A \wedge B|.

Now expand the difference:

SamMax=2i=0Kseg(ni)seg(n0)i=0K1ham(ni,ni+1)seg(nK).\text{Sam} - \text{Max} = 2\sum_{i=0}^{K} \text{seg}(n_i) - \text{seg}(n_0) - \sum_{i=0}^{K-1}\text{ham}(n_i, n_{i+1}) - \text{seg}(n_K).

Rewriting: SamMax=seg(n0)+2i=1K1seg(ni)+seg(nK)i=0K1ham(ni,ni+1)\text{Sam} - \text{Max} = \text{seg}(n_0) + 2\sum_{i=1}^{K-1}\text{seg}(n_i) + \text{seg}(n_K) - \sum_{i=0}^{K-1}\text{ham}(n_i, n_{i+1}).

Using seg(ni)+seg(ni+1)=ham(ni,ni+1)+2common(ni,ni+1)\text{seg}(n_i) + \text{seg}(n_{i+1}) = \text{ham}(n_i, n_{i+1}) + 2\,\text{common}(n_i, n_{i+1}), we telescope:

SamMax=2i=0K1common(ni,ni+1).\text{Sam} - \text{Max} = 2\sum_{i=0}^{K-1}\text{common}(n_i, n_{i+1}). \quad \square

Editorial

For primes p in (10^7, 210^7), compute the total difference Sam(p) - Max(p) where: The difference at each transition = 2 * (common segments). Seven-segment display: a | | f b |g| | | e c |d|. We sieve primes in (10^7, 210^7) using Sieve of Eratosthenes. We then iterate over each prime p. Finally, return global sum.

Pseudocode

Input: primes p in (10^7, 2*10^7)
Output: sum of Sam(p) - Max(p) over all such primes
Sieve primes in (10^7, 2*10^7) using Sieve of Eratosthenes
Precompute seg_count[d] and bitmask[d] for d = 0..9
For each prime p:
Return global sum

Complexity Analysis

  • Time: O(NloglogN)O(N \log \log N) for the sieve where N=2×107N = 2 \times 10^7. Per prime: O(logp)O(\log p) for the chain (at most 3—4 steps, each with 8\le 8 digits). Total: O(NloglogN)O(N \log \log N).
  • Space: O(N)O(N) for the sieve.

Answer

13625242\boxed{13625242}

Code

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

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

// Problem 315: Digital Root Clocks
// For each prime p in (10^7, 2*10^7), compute Sam(p) - Max(p)
// where Sam and Max display the digital root chain on 7-segment displays.
// Sam turns everything off then on; Max only changes differing segments.
// Difference = 2 * (common segments at each transition).

int main() {
    const int LO = 10000000;   // 10^7
    const int HI = 20000000;   // 2*10^7

    // Segment bitmasks for digits 0-9 (matching the Project Euler display)
    // Bits: a=0(top), b=1(top-right), c=2(bot-right), d=3(bot), e=4(bot-left), f=5(top-left), g=6(mid)
    // Key: digit 7 has 4 segments (a,b,c,f) including top-left vertical
    // 0:a,b,c,d,e,f(6) 1:b,c(2) 2:a,b,d,e,g(5) 3:a,b,c,d,g(5) 4:b,c,f,g(4)
    // 5:a,c,d,f,g(5) 6:a,c,d,e,f,g(6) 7:a,b,c,f(4) 8:all(7) 9:a,b,c,d,f,g(6)
    const int seg[10] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x27, 0x7f, 0x6f};

    // Precompute segment count and common segments between digits
    int seg_count[10];
    int common[10][10];
    for (int i = 0; i < 10; i++) {
        seg_count[i] = __builtin_popcount(seg[i]);
        for (int j = 0; j < 10; j++) {
            common[i][j] = __builtin_popcount(seg[i] & seg[j]);
        }
    }

    // Function to compute total segments for a number
    auto total_segs = [&](int n) -> int {
        if (n == 0) return seg_count[0];
        int s = 0;
        while (n > 0) {
            s += seg_count[n % 10];
            n /= 10;
        }
        return s;
    };

    // Function to compute common segments between two numbers
    // (digit by digit, right-aligned; missing digits have 0 common)
    auto common_segs = [&](int a, int b) -> int {
        int s = 0;
        while (a > 0 && b > 0) {
            s += common[a % 10][b % 10];
            a /= 10;
            b /= 10;
        }
        return s;
    };

    // Function to compute digit sum
    auto digit_sum = [](int n) -> int {
        int s = 0;
        while (n > 0) {
            s += n % 10;
            n /= 10;
        }
        return s;
    };

    // Sieve of Eratosthenes
    vector<bool> is_composite(HI, false);
    for (int i = 2; (long long)i * i < HI; i++) {
        if (!is_composite[i]) {
            for (int j = i * i; j < HI; j += i) {
                is_composite[j] = true;
            }
        }
    }

    long long answer = 0;

    for (int p = LO + 1; p < HI; p++) {
        if (is_composite[p]) continue;

        // Compute the digital root chain and accumulate 2 * common segments
        // Chain: p -> digit_sum(p) -> digit_sum(digit_sum(p)) -> ... -> single digit

        int current = p;
        while (current >= 10) {
            int next = digit_sum(current);
            answer += 2 * common_segs(current, next);
            current = next;
        }
        // The chain also includes the initial turn-on and final turn-off,
        // but these are the same for Sam and Max, so they don't contribute
        // to the difference.
    }

    cout << answer << endl;

    return 0;
}