Задача состоит в том, чтобы просто увидеть, насколько быстрее вы можете вычислить n, выберите n / 2 (для четных n), чем встроенная функция в python. Конечно, для больших n это довольно большое число, поэтому вместо вывода целого числа вы должны вывести сумму цифр. Например, для n = 100000
, ответ 135702
. Ибо n=1000000
это так 1354815
.
Вот код Python:
from scipy.misc import comb
def sum_digits(n):
r = 0
while n:
r, n = r + n % 10, n / 10
return r
sum_digits(comb(n,n/2,exact=True))
Ваш результат (highest n on your machine using your code)/(highest n on your machine using my code)
. Ваш код должен завершиться через 60 секунд или меньше.
Ваша программа должна дать правильный вывод для всех четных n: 2 <= n <= (ваш самый высокий n)
Вы не можете использовать какой-либо встроенный код или библиотеки, которые вычисляют биномиальные коэффициенты или значения, которые можно быстро преобразовать в биномиальные коэффициенты.
Вы можете использовать любой язык по вашему выбору.
Ведущий ответ Текущий ведущий ответ с удивительным 680.09 - по меньшей мере половиной.
n
миллионы, хотя я сомневаюсь, что функция Python справится с чем-то большим, чемn = 1e5
без удушья.Ответы:
C ++ (GMP) - (287 000 000/422 000) = 680,09
Бесстыдно объединить теорему Куммера с помощью xnor и GMP с помощью qwr.
Все еще даже близко к решению Go, не знаю почему.Изменить: Спасибо Кит Рэндалл за напоминание о том, что умножение быстрее, если число схожи по размеру. Я реализовал многоуровневое умножение, подобное концепции объединения памяти при управлении памятью. И результат впечатляет. То, что раньше занимало 51 с, теперь занимает всего 0,5 с (т.е. 100-кратное улучшение !!)
Бег для
n=287,000,000
Код. Компилировать с
-lgmp -lgmpxx -O3
источник
n
18 с при вычислении центрального биномиального коэффициента, а остальные 37 при преобразовании результата в строку и суммировании цифры.Go, 33,96 = (16300000/480000)
Работает путем подсчета всех простых факторов в числителе и знаменателе и отмены соответствующих факторов. Умножает остатки, чтобы получить результат.
Более 80% времени уходит на преобразование в базу 10. Должен быть лучший способ сделать это ...
источник
Python 3 (8,8 = 2,2 миллиона / 0,25 миллиона)
Это в Python, который не известен скоростью, так что вы можете лучше перенести это на другой язык.
Генератор простых чисел, взятый из этого конкурса StackOverflow .
Основная идея алгоритма - использовать теорему Куммера для получения простой факторизации бинома. Для каждого простого числа мы учим его высшую силу, которая делит ответ, и умножаем бегущий продукт на эту силу простого. Таким образом, нам нужно только умножить один раз для каждого простого числа в простой факторизации ответа.
Вывод с разбивкой по времени:
Удивительно, но большую часть времени тратится на преобразование числа в строку для суммирования его цифр. Также удивительно, что преобразование в строку было намного быстрее, чем получение цифр из повторяющихся
%10
и//10
, несмотря на то, вся строка должна предположительно быть сохранена в памяти.Генерация простых чисел занимает незначительное время (и, следовательно, я не чувствую несправедливого копирования существующего кода). Суммирование цифр происходит быстро. Фактическое умножение занимает треть времени.
Учитывая, что суммирование цифр является ограничивающим фактором, возможно, алгоритм для умножения чисел в десятичном представлении сэкономит время в целом путем сокращения двоичного / десятичного преобразования.
источник
Ява (оценка 22500/365000 = 0,062)
У меня нет Python на этой машине, поэтому, если кто-то может выиграть это, я был бы благодарен. Если нет, придется подождать.
Основой этой реализации является
Узкое место - это дополнение для вычисления соответствующей части треугольника Паскаля (90% времени выполнения), поэтому использование лучшего алгоритма умножения действительно не поможет.
Обратите внимание, что то, что вызывает вопрос,
n
это то, что я называю2n
. Аргумент командной строки - это то, что вызывает вопросn
.источник
javac CodeGolf37270.java
) и выполняется с Java 1.8 (java CodeGolf37270 n
). Я не уверен, есть ли какие-либо варианты оптимизации, о которых я не знаю. Я не могу попробовать скомпилировать с Java 1.8, потому что он не устанавливается с моим пакетом Java ...GMP - 1500000/300000 = 5,0
Хотя этот ответ не будет конкурировать с ситами, иногда короткий код все же может давать результаты.
источник
Java, пользовательский класс больших целых чисел: 32,9 (120000000/365000)
Основной класс довольно прост:
Он опирается на большой целочисленный класс, который оптимизирован для умножения, и
toString()
оба являются существенными узкими местами в реализации сjava.math.BigInteger
.Большим узким местом является наивное умножение (60%), за которым следует другое умножение (37%) и просеивание (3%).
digsum()
Вызов незначителен.Производительность измерена с OpenJDK 7 (64 бит).
источник
Python 2 (PyPy), 1 134 000/486 000 = 2,32
Результат: 1,537,506
Интересный факт: узким местом вашего кода является добавление цифр, а не вычисление биномиального коэффициента.
источник
Ява (2 020 000/491 000) = 4,11
обновлено, ранее 2.24
Java
BigInteger
не самая быстрая программа обработки чисел, но она лучше, чем ничего.Кажется
n! / ((n/2)!^2)
, что основная формула для этого , но это похоже на кучу избыточного умножения.Вы можете получить значительное ускорение, исключив все основные факторы, найденные как в числителе, так и в знаменателе. Для этого я сначала запускаю простое простое сито. Затем для каждого простого числа я веду подсчет того, к какой силе он должен быть поднят. Увеличивать каждый раз, когда я вижу фактор в числителе, уменьшать для знаменателя.
Я работаю с двумя отдельно (и сначала), так как их легко сосчитать / исключить до факторинга.
Как только это будет сделано, у вас будет минимальное количество необходимых умножений, что хорошо, потому что умножение BigInt происходит медленно .
Да, и сумма вывода для n = 2020000 есть
2735298
, для целей проверки.источник