Без перебора всех атомов во Вселенной.
from math import prod
def digiter(n):
while n != 0: yield n % 10; n //= 10
n = 8817
last = 55527
step = [10] * 5 + [4] + [1] * 8 + [8] + [10] + [20] # кольцо внутри сотни
cnt = 0
i = 0
while n 35)
n += 100
dl = list(digiter(n))
else:
dp = prod(dl)
if dp > 35: cnt += 1
n += step[i % len(step)]
i += 1
print(last, cnt)
Внутри каждой сотни выбираем не все числа подряд, а только те, которые содержат 7 и не содержат 0 в младших разрядах (произведения с нулём уж точно не превышают 35). Для этого строим кольцо из шагов: 17 + 10 = 27, 27 + 10 = 37, 67 + 4 = 71, 79 + 8 = 87, и т.д. В каждую сотню мы попадаем, начиная с 17, и последнее число в сотне - 97, всего их - 17 шт.
Если в старшем разряде ноль (например, 11017), то нет смысла бежать по всей сотне или тысяче: пропускаем сразу 100 или 1100 элементов.
Рано или поздно обход попадёт внутрь диапазона чисел, содержащих семёрку в третьем или четвёртом разрядах, например, 11717. Эти случаи отлавливаем и запускаем полный перебор внутри сотни, т.е. от 11711 до 11799. То же делаем в последующих сотнях, пока остаётся семёрка в старшем разряде.
На выходе:
55527 10958
Реализовано в виде конечного автомата с четырьмя ветвями обработки.
Количество итераций в этом алгоритме - не 55536 - 8800 = 46736, а около 11789 (включая однострочный for в ветке полного перебора), что лишь на 7.6% превосходит общее количество найденных чисел. Эти 7.6% - числа с малым произведением цифр (например, 11711) и нулевыми цифрами в полном переборе (например, 11720).
Можно сделать алгоритм и побыстрее, однократно вычисляя количество чисел в каждой сотне с нужным произведением цифр, но он при этом заметно усложнится.