Totient Chains
Let phi denote Euler's totient function. The totient chain of n is: n -> phi(n) -> phi(phi(n)) ->... -> 1 The length of the chain is the number of elements (including n and 1). For example, the cha...
Problem Statement
This archive keeps the full statement, math, and original media on the page.
Let \(\phi \) be Euler’s totient function, i.e. for a natural number \(n\), \(\phi (n)\) is the number of \(k\), \(1 \le k \le n\), for which \(\gcd (k, n) = 1\).
By iterating \(\phi \), each positive integer generates a decreasing chain of numbers ending in \(1\).
E.g. if we start with \(5\) the sequence \(5,4,2,1\) is generated.
Here is a listing of all chains with length \(4\): \begin {align*} 5,4,2,1&\\ 7,6,2,1&\\ 8,4,2,1&\\ 9,6,2,1&\\ 10,4,2,1&\\ 12,4,2,1&\\ 14,6,2,1&\\ 18,6,2,1 \end {align*}
Only two of these chains start with a prime, their sum is \(12\).
What is the sum of all primes less than \(40000000\) which generate a chain of length \(25\)?
Problem 214: Totient Chains
Mathematical Foundation
Theorem 1 (Euler’s product formula). For with distinct primes ,
Proof. By inclusion-exclusion on the set , the count of integers coprime to is:
This follows from the Mobius inversion formula: , and the multiplicativity of .
Lemma 1 (Strict decrease). For all , . Moreover, when is even.
Proof. For , has at least one prime factor , so . If , then .
Theorem 2 (Well-definedness and computability of chain length). The totient chain of every terminates at 1. If denotes the chain length, then and for . Moreover, can be computed in order since .
Proof. Since for (Lemma 1), the sequence is strictly decreasing until it reaches 1 (since ). This guarantees termination. The recurrence is valid because the chain of is followed by the chain of . Since , processing in increasing order ensures is already computed when we compute .
Lemma 2 (Totient sieve correctness). Initialize for all . For each from 2 to : if (i.e., is prime), then for every multiple of with , set . After completion, equals Euler’s totient for all .
Proof. Each prime is identified when still equals (no smaller prime has modified it, since is prime). The update applies the factor for each prime . After all primes are processed, by Theorem 1.
Lemma 3 (Prime detection). After the totient sieve, is prime if and only if .
Proof. If is prime, . Conversely, if is composite with smallest prime factor , then for . For , .
Editorial
We totient sieve. We then chain length computation. Finally, sum primes with chain length 25. We first generate the primes required by the search, then enumerate the admissible combinations and retain only the values that satisfy the final test.
Pseudocode
Totient sieve
Chain length computation
Sum primes with chain length 25
Complexity Analysis
- Time: Totient sieve: (each composite is visited once per prime factor, and by Mertens’ theorem). Chain computation: . Prime summation: . Total: where .
- Space: for the and chain arrays.
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#include <bits/stdc++.h>
using namespace std;
int main() {
const int N = 40000000;
// Sieve for Euler's totient
vector<int> phi(N);
iota(phi.begin(), phi.end(), 0); // phi[i] = i
for (int i = 2; i < N; i++) {
if (phi[i] == i) { // i is prime
for (int j = i; j < N; j += i) {
phi[j] = phi[j] / i * (i - 1);
}
}
}
// Compute chain lengths
vector<int> chain(N, 0);
chain[1] = 1;
for (int i = 2; i < N; i++) {
chain[i] = 1 + chain[phi[i]];
}
// Sum primes with chain length 25
long long answer = 0;
for (int i = 2; i < N; i++) {
if (phi[i] == i - 1 && chain[i] == 25) { // i is prime and chain length is 25
answer += i;
}
}
cout << answer << endl;
return 0;
}
def solve():
N = 40_000_000
# Sieve for Euler's totient
phi = list(range(N))
for i in range(2, N):
if phi[i] == i: # i is prime
for j in range(i, N, i):
phi[j] = phi[j] // i * (i - 1)
# Compute chain lengths
chain = [0] * N
chain[1] = 1
for i in range(2, N):
chain[i] = 1 + chain[phi[i]]
# Sum primes with chain length 25
answer = 0
for i in range(2, N):
if phi[i] == i - 1 and chain[i] == 25:
answer += i
print(answer)
if __name__ == "__main__":
solve()