Проект Эйлер-Задача 160

для любого N пусть f (N) - последние пять цифры перед конечными нулями Н!. Например,

9!  = 362880 so f(9)=36288 
10! = 3628800 so f(10)=36288 
20! = 2432902008176640000 so f(20)=17664

найти f (1,000,000,000,000)

Я успешно решил этот вопрос для приведенных примеров, моя функция может правильно найти f(9), f (10) и т. д. Однако он борется с большими числами, особенно с числом, которое требует проблема-f (10^12).

мои текущие оптимизации следующие: я удаляю конечные нули из множитель и сумма, и сократить сумму до 5 знаков после каждого умножения. Код в python выглядит следующим образом:

def SFTR (n):
 sum, a = 1, 2
 while a < n+1:
  mul  = int(re.sub("0+$","",str(a)))
  sum *= mul
  sum  = int(re.sub("0+$","",str(sum))[-5:])
  a   += 1
 return sum 

может ли кто-нибудь сказать мне, почему эта функция масштабируется так широко, и почему это занимает так много времени. Также, если кто-нибудь может намекнуть мне в правильном направлении, чтобы оптимизировать мой алгоритм. (название общей темы будет достаточно) Спасибо.

обновление:

я внес некоторые изменения для оптимизации, и это значительно быстрее, но все равно недостаточно быстро для f(10^12). Может ли кто-нибудь сказать мне, что делает мой код медленным или как сделать его быстрее?

def SFTR (n):
    sum, a = 1, 2
    while a < n+1:
        mul  = a

        while(mul % 10 == 0): mul = mul/10
        mul  = mul % 100000

        sum *= mul

        while(sum % 10 == 0): sum = sum/10
        sum  = sum % 100000

        a   += 1
    return sum

3 ответов


mul может стать очень большим. Это необходимо? Если бы я попросил вас вычислить последние 5 ненулевых цифр 1278348572934847283948561278387487189900038 * 38758 вручную, сколько именно цифр первого числа вам действительно нужно знать?


построение строк часто дорого. Я бы предпочел использовать оператор по модулю при усечении до последних пяти цифр.

python -m timeit 'x = str(111111111111111111111111111111111)[-5:]'
1000000 loops, best of 3: 1.09 usec per loop
python -m timeit 'x = 111111111111111111111111111111111 % 100000'
1000000 loops, best of 3: 0.277 usec per loop

то же самое относится к зачистке конечных нулей. Должен быть более эффективный способ сделать это, и вам, вероятно, не нужно делать это на каждом шагу.

Я не проверял ваш алгоритм на правильность, хотя это всего лишь подсказка для оптимизации.


фактически, вы можете даже отметить, что существует только ограниченный набор возможных конечных ненулевых цифр. Если я правильно помню, есть только несколько тысяч возможных комбинаций с ненулевыми цифрами, когда вы смотрите только на последние 5 цифр. Например, возможно ли, чтобы конечная ненулевая цифра когда-либо была нечетной? (Игнорируйте особые случаи 0! и 1! здесь.)