Sums of Totients of Powers
Let varphi denote Euler's totient function. Compute sum_(n=1)^N varphi(n^k) for given N and k. The specific instance asks for sum_(n=1)^(5 x 10^8) varphi(n) (i.e., k = 1).
Problem Statement
This archive keeps the full statement, math, and original media on the page.
Let \(\varphi (n)\) be Euler’s totient function.
Let \(f(n)=(\displaystyle {\sum }_{i=1}^{n}\varphi (n^i)) \bmod (n+1)\).
Let \(g(n)=\displaystyle {\sum }_{i=1}^{n} f(i)\).
You are given that \(g(100)=2007\).
Find \(g(5 \times 10^8)\).
Problem 512: Sums of Totients of Powers
Mathematical Foundation
Theorem 1 (Power Reduction). For all positive integers and ,
Proof. Let be the prime factorization of . Then , so
Theorem 2 (Gauss Identity). For all positive integers ,
Proof. Partition by : for each divisor , exactly integers in satisfy . Summing over all divisors yields . Since the sum over divisors is symmetric, .
Lemma 1 (Summatory Totient Recursion). Define . Then
Proof. Sum the Gauss identity over :
Wait — more carefully, exchanging the order of summation:
The correct derivation: from , summing over :
This does not directly give the recursion for . Instead, use the Dirichlet hyperbola approach:
Wait — that’s also not correct as stated. The standard derivation proceeds as follows. Define (Dirichlet convolution), so by Gauss. Then . Thus:
Isolating the term: .
Theorem 3 (Sublinear Evaluation). Using the recursion in Lemma 1 with memoization and the fact that takes distinct values, can be computed in time after pre-sieving for .
Proof. The number of distinct values of for is at most . Pre-sieving for costs time and provides all for by prefix summation. The remaining recursive calls each require work to group the sum by distinct values of , giving total work .
Editorial
Compute sum of phi(n^k) for n = 1..N, using phi(n^k) = n^(k-1) * phi(n). Efficient totient sieve and sublinear summation. We pre-sieve phase.
Pseudocode
Pre-sieve phase
Set B <- floor(N^(2/3))
Set phi[1..B] <- Euler_sieve(B) // O(B log log B)
Set Phi_small[i] <- prefix_sum(phi, i) // for i = 1..B
Set memo <- empty hash map
if m <= B: return Phi_small[m]
if m in memo: return memo[m]
Set result <- m * (m + 1) / 2
Set d <- 2
While d <= m:
Set q <- floor(m / d)
Set d_max <- floor(m / q)
result -= (d_max - d + 1) * Phi(q)
Set d <- d_max + 1
Set memo[m] <- result
Return result
Return Phi(N)
For the general case, compute using a sieve of and direct summation.
## Complexity Analysis
- **Sieve approach (general $k$):** $O(N \log\log N)$ time, $O(N)$ space.
- **Sublinear method ($k = 1$):** $O(N^{2/3})$ time, $O(N^{2/3})$ space.
## Answer
$$
\boxed{50660591862310323}
$$ Code
Each problem page includes the exact C++ and Python source files from the local archive.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// Totient sieve: compute phi(n) for all n in [0, N]
vector<int> totient_sieve(int N) {
vector<int> phi(N + 1);
iota(phi.begin(), phi.end(), 0); // phi[n] = n
for (int p = 2; p <= N; p++) {
if (phi[p] == p) { // p is prime
for (int m = p; m <= N; m += p) {
phi[m] = phi[m] / p * (p - 1);
}
}
}
return phi;
}
// Sum of phi(n^k) = sum of n^(k-1) * phi(n) for n = 1..N
ll sum_totient_powers(int N, int k) {
auto phi = totient_sieve(N);
ll total = 0;
for (int n = 1; n <= N; n++) {
ll nk = 1;
for (int j = 0; j < k - 1; j++) nk *= n; // n^(k-1)
total += nk * phi[n];
}
return total;
}
// Sublinear sum of phi(n) for n = 1..N
// O(N^{2/3}) using the hyperbola method
ll sum_totient_sublinear(ll N) {
if (N <= 1) return N;
int cbrt_N = (int)cbrt((double)N) + 1;
int small = min((ll)cbrt_N * cbrt_N, N);
// If N is too large for sieve, limit small
if (small > 5000000) small = 5000000;
small = min(small, (int)N);
auto phi = totient_sieve(small);
vector<ll> prefix(small + 1, 0);
for (int i = 1; i <= small; i++) {
prefix[i] = prefix[i-1] + phi[i];
}
unordered_map<ll, ll> memo;
function<ll(ll)> Phi = [&](ll n) -> ll {
if (n <= small) return prefix[n];
auto it = memo.find(n);
if (it != memo.end()) return it->second;
ll result = n * (n + 1) / 2;
ll d = 2;
while (d <= n) {
ll q = n / d;
ll d_next = n / q + 1;
result -= (d_next - d) * Phi(q);
d = d_next;
}
memo[n] = result;
return result;
};
return Phi(N);
}
int main() {
// Compute sum of phi(n) for n = 1..N
int N = 10000;
auto phi = totient_sieve(N);
// Display first 20
cout << "First 20 totient values:" << endl;
for (int n = 1; n <= 20; n++) {
cout << " phi(" << n << ") = " << phi[n] << endl;
}
// Sum phi(n)
ll sum1 = 0;
for (int n = 1; n <= N; n++) sum1 += phi[n];
cout << "\nSum phi(n) for n=1.." << N << ": " << sum1 << endl;
// Sum phi(n^2) = sum n*phi(n)
ll sum2 = sum_totient_powers(N, 2);
cout << "Sum phi(n^2) for n=1.." << N << ": " << sum2 << endl;
// Sublinear
ll N_large = 1000000;
ll sub = sum_totient_sublinear(N_large);
cout << "\nSum phi(n) for n=1.." << N_large << ": " << sub << endl;
return 0;
}
"""
Problem 512: Sums of Totients of Powers
Compute sum of phi(n^k) for n = 1..N, using phi(n^k) = n^(k-1) * phi(n).
Efficient totient sieve and sublinear summation.
"""
import numpy as np
def totient_sieve(N: int) -> list:
"""
Compute phi(n) for all n from 0 to N using a sieve.
O(N log log N) time, O(N) space.
"""
phi = list(range(N + 1)) # phi[n] = n initially
for p in range(2, N + 1):
if phi[p] == p: # p is prime
for m in range(p, N + 1, p):
phi[m] = phi[m] // p * (p - 1)
return phi
def sum_totient_powers_sieve(N: int, k: int):
"""
Compute sum of phi(n^k) for n = 1..N.
Uses phi(n^k) = n^(k-1) * phi(n).
"""
phi = totient_sieve(N)
total = 0
for n in range(1, N + 1):
total += pow(n, k - 1) * phi[n]
return total
def sum_totient_sublinear(N: int):
"""
Compute sum of phi(n) for n = 1..N in O(N^{2/3}) time.
Uses the identity: sum_{n=1}^{N} phi(n) = N*(N+1)/2 - sum_{d=2}^{N} Phi(floor(N/d))
"""
if N <= 0:
return 0
# For small values, use sieve
cbrt_N = int(N ** (2/3)) + 1
small_limit = min(cbrt_N, N)
phi_small = totient_sieve(small_limit)
prefix = [0] * (small_limit + 1)
for i in range(1, small_limit + 1):
prefix[i] = prefix[i-1] + phi_small[i]
memo = {}
def Phi(n):
if n <= small_limit:
return prefix[n]
if n in memo:
return memo[n]
result = n * (n + 1) // 2
d = 2
while d <= n:
q = n // d
d_next = n // q + 1
result -= (d_next - d) * Phi(q)
d = d_next
memo[n] = result
return result
return Phi(N)
def brute_force_totient_sum(N: int):
"""Brute-force sum of phi(n) for verification."""
phi = totient_sieve(N)
return sum(phi[1:N+1])
# Verify sieve
N_test = 100
phi = totient_sieve(N_test)
print("First 20 totient values:")
for n in range(1, 21):
print(f" phi({n}) = {phi[n]}")
# Verify sum
sum_sieve = brute_force_totient_sum(N_test)
sum_sub = sum_totient_sublinear(N_test)
print(f"\nSum of phi(n) for n=1..{N_test}:")
print(f" Sieve: {sum_sieve}")
print(f" Sublinear: {sum_sub}")
print(f" Match: {'YES' if sum_sieve == sum_sub else 'NO'}")
# Sum of phi(n^2) = sum of n * phi(n)
N_main = 10000
total_k1 = sum_totient_powers_sieve(N_main, 1)
total_k2 = sum_totient_powers_sieve(N_main, 2)
total_k3 = sum_totient_powers_sieve(N_main, 3)
print(f"\nFor N = {N_main}:")
print(f" Sum phi(n) = {total_k1}")
print(f" Sum phi(n^2) = {total_k2}")
print(f" Sum phi(n^3) = {total_k3}")
# Sublinear for larger N
N_large = 10**6
large_sum = sum_totient_sublinear(N_large)
print(f"\nSum phi(n) for n=1..{N_large}: {large_sum}")
# Known: sum phi(n) for n=1..N ~ 3N^2/pi^2
approx = 3 * N_large**2 / (np.pi**2)
print(f" Approximation 3N^2/pi^2 = {approx:.0f}")
print(f" Ratio: {large_sum / approx:.6f}")