We do not need simple factorization or inclusion-exception to solve this problem. We can modify the Euler sieve to dynamically calculate the Euler totalizer using its product formula, leading to the O(n) algorithm.
For each number in our accumulative list, we also store its totality. We use the fact that for the tuple (n, phi(n)) , where phi is the Euler function in magnitude:
if m = p * n, for prime p: if p does not divide n then phi(m) = (p - 1) * phi(n) else phi(m) = p * phi(n)
(Note that primes are generated as part of this algorithm by simply increasing the pointer to the next number not yet listed.)
For example n = 12 :
list = [(2,1)] total = 1 prime: 2 2*2: (2 * 2, 2 * 1) total = total + 2 list: [(2,1), (4,2)] 2*2*2: (2 * 4, 2 * 2) total = total + 4 list: [(2,1), (4,2), (8,4)] prime: 3 total = total + 2 list: [(2,1), (3,2), (4,2), (8,4)] 3*3: (3 * 3, 3 * 2) total = total + 6 list: [(2,1), (3,2), (4,2), (8,4), (9,6)] 3*2: (3 * 2, 1 * (3-1)) total = total + 2 list: [(2,1), (3,2), (4,2), (6,2), (8,4), (9,6)] 3*4: (3 * 4, 2 * (3-1)) total = total + 4 list: [(2,1), (3,2), (4,2), (6,2), (8,4), (9,6), (12,4)] prime: 5 total = total + 4 list: [(2,1), (3,2), (4,2), (5,4), (6,2), (8,4), (9,6), (12,4)] 5*2: (5 * 2, 1 * (5-1)) total = total + 4 list: [(2,1), (3,2), (4,2), (5,4), (6,2), (8,4), (9,6), (10,4), (12,4)] prime: 7 total = total + 6 list: [(2,1), (3,2), (4,2), (5,4), (6,2), (7,6), (8,4), (9,6), (10,4), (12,4)] prime: 11 total = total + 10 list: [(2,1), (3,2), (4,2), (5,4), (6,2), (7,6), (8,4), (9,6), (10,4), (11,10), (12,4)]
Python code (this code is actually an adaptation of the code from btilly, optimizing my idea):
n = 8 total = 0 a = [None for i in range(0, n+1)] s = [] p = 1 while (p < n): p = p + 1 if a[p] is None: print("\n\nPrime: " + str(p)) a[p] = p - 1 total = total + a[p] s.append(p) limit = n / p new_s = [] for i in s: j = i while j <= limit: new_s.append(j) print j*p, a[j] a[j * p] = a[j] * p if (not j % p) else a[j] * (p-1) total = total + a[j * p] j = j * p s = new_s print("\n\nAnswer: " + str(total) + " => " + str([(k,d) for k,d in enumerate(a)]))