Не получается решить задачу с поиском делителей

Найдите все натуральные числа, принадлежащие отрезку [1 000 000; 5 000 000], у которых ровно десять различных делителей, пять из которых четные и пять нечетные. В ответе перечислите найденные числа в порядке возрастания. Каждое число вводится в новое поле.

У меня получился такой код, но он долго выполняется и в итоге ничего не выдает

from sympy import divisors
from collections import Counter

def count_divisors(num):
    divs = divisors(num)
    div_counts = Counter(div % 2 for div in divs)
    return sum(div_counts[0] == 5 and div_counts[1] == 5 for num in range(1000000, 5000001))

valid_numbers = [num for num in range(1000000, 5000001) if count_divisors(num) == 1]
print(valid_numbers)

Ответы (1 шт):

Автор решения: Stanislav Volodarskiy

Цикл в операторе return лишний. Так будет работать, хотя и медленно:

from sympy import divisors
from collections import Counter


def count_divisors(num):
    divs = divisors(num)
    div_counts = Counter(div % 2 for div in divs)
    return div_counts[0] == 5 and div_counts[1] == 5


valid_numbers = [num for num in range(1000000, 5000001) if count_divisors(num)]
print(valid_numbers)

Две минуты:

$ time python temp.py
[1414562, 1847042, 3748322]

real  2m5.528s
user  2m5.456s
sys   0m0.020s

Проще и быстрее сосчитать делители напрямую:

n = 5000001
even = [0] * n
for i in range(2, n, 2):
    for j in range(i, n, i):
        even[j] += 1

odd = [0] * n
for i in range(1, n, 2):
    for j in range(i, n, i):
        odd[j] += 1

for i in range(1000000, n):
    if even[i] == odd[i] == 5:
        print(i)

Четырнадцать секунд:

$ time python temp.py
1414562
1847042
3748322

real  0m14.110s
user  0m13.948s
sys   0m0.012s

С другой стороны пять нечётных делителей имеют только числа вида 2kp4, где p нечётное простое (подробности в статье Функция делителей на Википедии). Из них пять чётных делителей имеют числа вида 2p4. Такие числа перебрать можно очень быстро.

В программе ниже неэффективная простая проверка числа на простоту потому что проверять большие числа не нужно:

n = 5000000
for p in range(3, n + 1, 2):
    m = 2 * p ** 4
    if m > n:
        break
    if m >= 1000000 and all(p % i != 0 for i in range(3, p, 2)):
        print(m)
$ time python temp.py
1414562
1847042
3748322

real  0m0.044s
user  0m0.036s
sys   0m0.004s
→ Ссылка