Totient Permutation
Find the value of n, 1 < n < 10^7, for which varphi(n) is a permutation of the digits of n and the ratio n/varphi(n) is minimized.
Problem Statement
This archive keeps the full statement, math, and original media on the page.
Euler’s totient function, \(\phi (n)\) [sometimes called the phi function], is used to determine the number of positive numbers less than or equal to \(n\) which are relatively prime to \(n\). For example, as \(1, 2, 4, 5, 7\), and \(8\), are all less than nine and relatively prime to nine, \(\phi (9)=6\).
The number \(1\) is considered to be relatively prime to every positive number, so \(\phi (1)=1\).
Interestingly, \(\phi (87109)=79180\), and it can be seen that \(87109\) is a permutation of \(79180\).
Find the value of \(n\), \(1 < n < 10^7\), for which \(\phi (n)\) is a permutation of \(n\) and the ratio \(n/\phi (n)\) produces a minimum.
Problem 70: Totient Permutation
Mathematical Analysis
Theorem 1 (Ratio Formula)
For :
Proof. Follows directly from .
Theorem 2 (Minimization Principles)
To minimize subject to the permutation constraint:
- Use as few distinct prime factors as possible (each factor increases the ratio).
- Use primes as large as possible ( as ).
Proof. Statement (1): If has distinct prime factors, then in the worst case, and is always for . Fewer factors yield a smaller product.
Statement (2): Among ratios with the same number of prime factors, is minimized by choosing the largest possible primes (since is strictly decreasing).
Theorem 3 (Exclusion of Primes)
If is prime, then is never a digit permutation of .
Proof. Two integers are digit permutations of each other only if they are congruent modulo 9 (since the digit sum is invariant under permutation, and a number is congruent to its digit sum mod 9). However, , so , meaning (as ). Therefore and cannot be digit permutations.
Corollary (Semiprimes Are Optimal Candidates)
Since primes are excluded by Theorem 3, the candidates with the fewest prime factors are semiprimes (with distinct primes or ). For semiprimes:
This ratio is minimized when and are large and close to .
Proof. For fixed product , the ratio is minimized when and are as close as possible (by AM-GM, the denominator is maximized for ). Furthermore, larger primes yield a ratio closer to 1.
Remark on
For , we have and , which has only one prime factor contributing. However, the permutation constraint is hard to satisfy for large , and in practice the semiprime form with yields the optimum.
Search Strategy
Proposition. It suffices to search over pairs of primes with and . For each pair, check whether is a digit permutation of , and track the pair minimizing .
Proof of sufficiency. By Theorem 3, cannot be prime. If has three or more distinct prime factors, then , whereas the semiprime candidate yields a ratio near 1. Products of prime powers with three or more factors are similarly dominated. Hence we need only search semiprimes.
Digit Permutation Criterion
Lemma. Two positive integers and are digit permutations of each other if and only if they have the same multiset of decimal digits, equivalently, the same sorted digit string.
Proof. By definition.
Editorial
The search is restricted to semiprimes , because the ratio is minimized there among non-prime candidates, especially when and are large and close to . We enumerate prime pairs with and , compute , and test whether is a digit permutation of . Among all pairs passing that test, we keep the one with the smallest ratio .
Pseudocode
Generate the primes below the search bound.
Begin with no candidate and with the best ratio larger than every feasible value.
For each prime p whose square is still below 10^7:
pair p with primes q starting from p itself
stop the inner scan once pq reaches the bound
for each admissible product n = pq:
compute phi(n) = (p - 1)(q - 1)
compare the decimal digit multisets of n and phi(n)
if they are permutations of one another and the ratio n / phi(n) improves the current best:
record this n as the new best candidate
Return the recorded best candidate.
Complexity
- Sieve: where .
- Search: pairs. By the Prime Number Theorem, , so this is .
- Space: for the prime 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;
bool is_permutation(int a, int b) {
int digits_a[10] = {}, digits_b[10] = {};
while (a > 0) { digits_a[a % 10]++; a /= 10; }
while (b > 0) { digits_b[b % 10]++; b /= 10; }
for (int i = 0; i < 10; i++)
if (digits_a[i] != digits_b[i]) return false;
return true;
}
int main() {
const int LIMIT = 10000000;
// Sieve of Eratosthenes
vector<bool> is_prime(LIMIT, true);
is_prime[0] = is_prime[1] = false;
for (int i = 2; (long long)i * i < LIMIT; i++) {
if (is_prime[i]) {
for (int j = i * i; j < LIMIT; j += i)
is_prime[j] = false;
}
}
vector<int> primes;
for (int i = 2; i < LIMIT; i++) {
if (is_prime[i]) primes.push_back(i);
}
double best_ratio = 1e18;
int best_n = 0;
// Search semiprimes n = p * q with p <= q, pq < LIMIT
for (int i = 0; i < (int)primes.size(); i++) {
int p = primes[i];
if ((long long)p * p >= LIMIT) break;
for (int j = i; j < (int)primes.size(); j++) {
int q = primes[j];
long long n = (long long)p * q;
if (n >= LIMIT) break;
long long phi = (long long)(p - 1) * (q - 1);
double ratio = (double)n / phi;
if (ratio < best_ratio && is_permutation((int)n, (int)phi)) {
best_ratio = ratio;
best_n = (int)n;
}
}
}
cout << best_n << endl;
return 0;
}
"""
Project Euler Problem 70: Totient Permutation
Find n, 1 < n < 10^7, for which phi(n) is a digit permutation of n
and n/phi(n) is minimized.
By Theorem 3, primes are excluded. By the Corollary, semiprimes n = p*q
with p, q near sqrt(10^7) are optimal candidates.
"""
def sieve_primes(limit):
"""Sieve of Eratosthenes returning list of primes up to limit."""
is_prime = bytearray(b'\x01') * (limit + 1)
is_prime[0] = is_prime[1] = 0
for i in range(2, int(limit**0.5) + 1):
if is_prime[i]:
is_prime[i*i::i] = bytearray(len(is_prime[i*i::i]))
return [i for i in range(2, limit + 1) if is_prime[i]]
def is_permutation(a, b):
"""Check if a and b have the same multiset of decimal digits."""
return sorted(str(a)) == sorted(str(b))
def main():
LIMIT = 10_000_000
primes = sieve_primes(LIMIT)
best_ratio = float('inf')
best_n = 0
for i in range(len(primes)):
p = primes[i]
if p * p >= LIMIT:
break
for j in range(i, len(primes)):
q = primes[j]
n = p * q
if n >= LIMIT:
break
phi = (p - 1) * (q - 1)
ratio = n / phi
if ratio < best_ratio and is_permutation(n, phi):
best_ratio = ratio
best_n = n
print(best_n)
if __name__ == "__main__":
main()