Довольно поздно на вечеринку, но в любом случае, вот мое решение. Извините, это на Python, а не на C ++, но его должно быть относительно легко перевести. И поскольку это в первую очередь проблема алгоритма, я надеюсь, что все в порядке.
Что касается проблемы переполнения, то единственное, что приходит на ум, - это использовать массивы цифр вместо реальных чисел. Учитывая этот алгоритм, я надеюсь, что он не сильно повлияет на производительность.
https://gist.github.com/frnhr/7608873
Он использует эти три рекурсии, которые я обнаружил, глядя на проблему. Вместо того, чтобы пытаться придумать некоторые общие и загадочные уравнения, вот три примера. Общий случай должен быть легко виден из тех.
отношение 1
Сокращает количество вызовов функций с произвольным аргументом до нескольких рекурсивных вызовов с более предсказуемыми аргументами для использования в отношениях 2 и 3.
foo(3456) == foo(3000)
+ foo(400) + 400 * (3)
+ foo(50) + 50 * (3 + 4)
+ foo(6) + 6 * (3 + 4 + 5)
Отношение 2
Сокращение вызовов с аргументом в форме L*10^M
(например, 30, 7000, 900000) до рекурсивного вызова, используемого для отношения 3. Эти треугольные числа появились совершенно незваными (но приветствуются) :)
triangular_numbers = [0, 1, 3, 6, 10, 15, 21, 28, 36] # 0 not used
foo(3000) == 3 * foo(1000) + triangular_numbers[3 - 1] * 1000
Полезно только если L > 1
. Это верно для L = 1
, но тривиально. В этом случае перейдите непосредственно к соотношению 3.
отношение 3
Рекурсивно сокращать вызовы с аргументом в формате 1*10^M
до вызова с аргументом, который делится на 10.
foo(1000) == foo(100) * 10 + 44 * 100 + 100 - 9 # 44 and 9 are constants
В конечном итоге вам нужно только реально рассчитать сумму или цифры для чисел от 0 до 10, и получается, что требуется только до 3 из этих вычислений. Все остальное решается с помощью этой рекурсии. Я почти уверен, что он запускается в O(logN)
время. Это ФАСТ !!!!! 11one
На моем ноутбуке он вычисляет сумму цифр для данного числа с более чем 1300 цифрами менее чем за 7 секунд! Ваш тест (1000000000000000000) рассчитывается за 0,000112057 секунд!