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...
Problem Statement
This archive keeps the full statement, math, and original media on the page.
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
| Number | Transitions | |
| "137" |
| |
| "11" |
| |
| "2" |
|
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
| Number | Transitions | |||
| "137" |
| |||
| "11" |
| |||
| "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 :
| Digit | Segments | Count | Bitmask |
|---|---|---|---|
| 0 | a,b,c,d,e,f | 6 | 0x3F |
| 1 | b,c | 2 | 0x06 |
| 2 | a,b,d,e,g | 5 | 0x5B |
| 3 | a,b,c,d,g | 5 | 0x4F |
| 4 | b,c,f,g | 4 | 0x66 |
| 5 | a,c,d,f,g | 5 | 0x6D |
| 6 | a,c,d,e,f,g | 6 | 0x7D |
| 7 | a,b,c,f | 4 | 0x27 |
| 8 | a,b,c,d,e,f,g | 7 | 0x7F |
| 9 | a,b,c,d,f,g | 6 | 0x6F |
Note: digit 7 uses 4 segments (including the top-left vertical ), per the Project Euler specification.
Definition (Segment Count Functions). For a number with digits , define:
- , the total number of active segments,
- = bitmask of digit .
Lemma 1 (Sam’s Cost). For the digital root chain (where , is a single digit), Sam’s total segment transitions are:
Proof. Sam turns on all segments of (cost ), then turns them all off (cost ), for each . Total: .
Lemma 2 (Max’s Cost). Max’s total segment transitions are:
where is the number of segments that differ between the right-aligned digit-by-digit bitmask representations of and (the Hamming distance of the composite bitmasks, padding shorter numbers with zero on the left).
Proof. Max initially turns on from blank (cost ). At each transition , Max toggles only the differing segments (cost ). Finally, Max turns off to blank (cost ).
Theorem (Difference Identity). For any two bitmasks and :
where is XOR (symmetric difference) and is AND (intersection). Consequently:
where is the number of segments shared between consecutive displays (computed digit-by-digit, right-aligned).
Proof. For bitmasks : every bit is either in , in , or in . The XOR counts bits in exactly one of ; the AND counts bits in both. So .
Now expand the difference:
Rewriting: .
Using , we telescope:
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: for the sieve where . Per prime: for the chain (at most 3—4 steps, each with digits). Total: .
- Space: for the sieve.
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#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;
}
"""
Problem 315: Digital Root Clocks
For primes p in (10^7, 2*10^7), compute the total difference
Sam(p) - Max(p) where:
- Sam turns off all segments then turns on new ones at each step
- Max only changes segments that differ
The difference at each transition = 2 * (common segments).
Seven-segment display:
_a_
| |
f b
|_g_|
| |
e c
|_d_|
"""
# Segment bitmasks: 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)
# NOTE: In the Project Euler display, digit 7 has 4 segments (includes top-left f).
SEGMENTS = {
0: 0x3f, # a,b,c,d,e,f = 6 segments
1: 0x06, # b,c = 2 segments
2: 0x5b, # a,b,d,e,g = 5 segments
3: 0x4f, # a,b,c,d,g = 5 segments
4: 0x66, # b,c,f,g = 4 segments
5: 0x6d, # a,c,d,f,g = 5 segments
6: 0x7d, # a,c,d,e,f,g = 6 segments
7: 0x27, # a,b,c,f = 4 segments
8: 0x7f, # a,b,c,d,e,f,g = 7 segments
9: 0x6f, # a,b,c,d,f,g = 6 segments
}
SEG_COUNT = {d: bin(SEGMENTS[d]).count('1') for d in range(10)}
def popcount(x):
"""Count set bits."""
return bin(x).count('1')
def common_segments(a, b):
"""Count common segments between displays of numbers a and b."""
total = 0
while a > 0 and b > 0:
total += popcount(SEGMENTS[a % 10] & SEGMENTS[b % 10])
a //= 10
b //= 10
return total
def digit_sum(n):
"""Sum of digits of n."""
s = 0
while n > 0:
s += n % 10
n //= 10
return s
def solve():
LO = 10_000_000
HI = 20_000_000
# Sieve of Eratosthenes
is_prime = bytearray([1]) * HI
is_prime[0] = is_prime[1] = 0
for i in range(2, int(HI**0.5) + 1):
if is_prime[i]:
is_prime[i*i::i] = bytearray(len(is_prime[i*i::i]))
answer = 0
for p in range(LO + 1, HI):
if not is_prime[p]:
continue
current = p
while current >= 10:
nxt = digit_sum(current)
answer += 2 * common_segments(current, nxt)
current = nxt
print(answer)
