Вот решение, которое более эффективно, чем сито Эратосфена.Он получен из аналогичных алгоритмов для подсчета простых чисел .Преимущество состоит в том, что нет необходимости находить все простые числа, чтобы найти их сумму.
Основная идея заключается в следующем: пусть S (v, m) будет суммой целых чисел в диапазоне 2..vкоторые остаются после просеивания со всеми простыми числами, меньшими или равными m.То есть S (v, m) - это сумма целых чисел до v, которые либо просты, либо являются произведением простых чисел, больших m.
S (v, p) равно S (v, p-1), если p не простое число или v меньше p * p.В противном случае (p prime, p * p <= v) S (v, p) может быть вычислено из S (v, p-1) путем нахождения суммы целых чисел, которые удаляются при просеивании с помощью p.На этом этапе удаляется целое число, если оно является произведением p на другое целое число, у которого нет делителя, меньшего, чем p.Это может быть выражено как </p>
$ S (v, p) = S (v, p-1) - p (S (v / p, p-1) - S (p-1, p-1)). $
Для этого можно использовать динамическое программирование.Достаточно вычислить S (v, p) для всех натуральных чисел v, которые представляются в виде floor (n / k) для некоторого целого числа k и всех $ p \ leq \ sqrt v $.
def P10(n):
r = int(n**0.5)
assert r*r <= n and (r+1)**2 > n
V = [n//i for i in range(1,r+1)]
V += list(range(V[-1]-1,0,-1))
S = {i:i*(i+1)//2-1 for i in V}
for p in range(2,r+1):
if S[p] > S[p-1]: # p is prime
sp = S[p-1] # sum of primes smaller than p
p2 = p*p
for v in V:
if v < p2: break
S[v] -= p*(S[v//p] - sp)
return S[n]
Сложность этого алгоритма составляет около $ O (n ^ {0.75}) $, и для его решения требуется 9 мс.