Теорема Лагранжа о четырех квадратах говорит нам, что любое натуральное число может быть представлено как сумма четырех квадратных чисел. Ваша задача - написать программу, которая делает это.
Ввод: натуральное число (ниже 1 миллиарда)
Вывод: четыре числа, чьи квадраты суммируются с этим числом (порядок не имеет значения)
Примечание: вам не нужно искать грубой силой! Подробности здесь и здесь . Если есть функция, которая тривиализирует эту проблему (я буду определять), это не разрешено. Автоматические простые функции и квадратный корень разрешены. Если есть более одного представления, то все в порядке. Если вы решили применить грубую силу, она должна быть запущена в течение разумного времени (3 минуты)
образец ввода
123456789
образец вывода (либо в порядке)
10601 3328 2 0
10601 3328 2
Ответы:
CJam, 50 байтов
Мой третий (и последний, я обещаю) ответ. Этот подход в значительной степени основан на ответе primo .
Попробуйте онлайн в интерпретаторе CJam .
использование
Фон
После просмотра обновленного алгоритма primo я должен был увидеть, как будет работать реализация CJam:
Всего 58 байт! Этот алгоритм работает в почти постоянное время и не демонстрирует большой разброс при различных значениях
N
. Давайте изменим это ...Вместо того, чтобы начинать с
floor(sqrt(N))
и уменьшать, мы можем начинать с1
и увеличивать. Это экономит 4 байта.Вместо того, чтобы выражать
N
как4**a * b
, мы можем выразить это какp**(2a) * b
- гдеp
наименьший простой факторN
- чтобы сохранить еще 1 байт.Предыдущая модификация позволяет слегка изменить реализацию (не касаясь сам алгоритм): Вместо деления
N
наp**(2a)
и умножить на решении,p**a
мы можем непосредственно ограничить возможные решения кратныхp**a
. Это экономит еще 2 байта.Не ограничивая первое целое число кратным,
p**a
сохраняет дополнительный байт.Окончательный алгоритм
Найти
a
иb
такое, чтоN = p**(2a) * b
, гдеb
не кратноp**2
иp
является наименьшим простым множителемN
.Set
j = p**a
.Set
k = floor(sqrt(N - j**2) / A) * A
.Set
l = floor(sqrt(N - j**2 - k**2) / A) * A
.Set
m = floor(sqrt(N - j**2 - k**2 - l**2) / A) * A
.Если
N - j**2 - k**2 - l**2 - m**2 > 0
, установитеj = j + 1
и вернитесь к шагу 3.Это может быть реализовано следующим образом:
Ориентиры
Я выполнил все 5 версий для всех натуральных чисел до 999 999 999 на моем Intel Core i7-3770, измерил время выполнения и посчитал количество итераций, необходимых для поиска решения.
В следующей таблице показано среднее количество итераций и время выполнения для одного целого числа:
Всего за 4 итерации и 6,6 микросекунды на целое число алгоритм primo невероятно быстр.
Начиная с
floor(sqrt(N))
более логично, так как мы получаем меньшие значения для суммы оставшихся трех квадратов. Как и ожидалось, начиная с 1 намного медленнее.Это классический пример плохо реализованной хорошей идеи. Чтобы уменьшить размер кода, мы полагаемся
mF
, что факторизирует целое числоN
. Хотя версия 3 требует меньше итераций, чем версия 2, на практике она намного медленнее.Хотя алгоритм не меняется, версия 4 намного медленнее. Это потому, что он выполняет дополнительное деление с плавающей запятой и целочисленное умножение в каждой итерации.
Для ввода
N = p**(2a) ** b
алгоритму 5 потребуются(k - 1) * p**a + 1
итерации, гдеk
число итераций, необходимое алгоритму 4. Еслиk = 1
илиa = 0
, это не имеет значения.Тем не менее, любой ввод формы
4**a * (4**c * (8 * d + 7) + 1)
может работать довольно плохо. Для начального значенияj = p**a
,N - 4**a = 4**(a + c) * (8 * d + 7)
поэтому его нельзя выразить как сумму трех квадратов. Таким образом,k > 1
и хотя быp**a
итерации не требуется.К счастью, оригинальный алгоритм Primo невероятно быстр и
N < 1,000,000,000
. Худший случай, который я мог найти вручную, -265,289,728 = 4**10 * (4**1 * (7 * 8 + 7) + 1)
это 6,145 итераций. Время выполнения составляет менее 300 мс на моей машине. В среднем эта версия в 13,5 раз медленнее, чем реализация алгоритма primo.источник
N
как4**a * b
мы можем выразить это какp**(2a) * b
». Это на самом деле улучшение . Я хотел бы включить это, но это было намного дольше (идеал - найти самый большой идеальный квадратный фактор). «Начиная с 1 и увеличивая, сохраняет 4 байта». Это определенно медленнее. Время выполнения для любого заданного диапазона в 4-5 раз больше. «Все положительные целые числа до 999 999 999 заняли 24,67 часа, что дает среднее время выполнения 0,0888 миллисекунд на целое число». Perl потребовалось всего 2,5 часа, чтобы сократить весь диапазон, и перевод на Python в 10 раз быстрее;)p**a
это улучшение, но оно небольшое. Деление на наибольший коэффициент идеального квадрата имеет большое значение, начиная с 1; это все еще улучшение, если начинать с целочисленной части квадратного корня. Реализация этого будет стоить всего два байта. Кажется, что ужасное время казни связано с моими улучшениями, а не с CJam. Я перезапущу тесты для всех алгоритмов (включая тот, который вы предложили), подсчитывая итерации, а не измеряя время стены. Давайте посмотрим, сколько времени это займет ...1\
меняет его на 1 (аккумулятор), увеличиваетmF
факторизацию и{~2/#*}/
увеличивает каждый простой множитель до его степени, деленной на два, а затем умножает его на аккумулятор. Для непосредственной реализации вашего алгоритма это добавляет только 2 байта. Небольшое отличие состоит в основном из - за неудобной , как я должен был найти экспоненту 4, так как CJam не (кажется,) имеют то время как петля ...ФРАКТРАН:
15698 фракцийПоскольку это классическая проблема теории чисел, что может быть лучше, чем использовать числа!
Принимает на входе форму 2 n × 193 и выводит 3 a × 5 b × 7 c × 11 d . Бегите за 3 минуты, если у вас действительно хороший переводчик. Может быть.
намек
Код эквивалентен следующему псевдопифону:
источник
Mathematica
61 6651Три метода показаны. Только первый подход соответствует требованию времени.
1-FindInstance (51 символ)
Это возвращает единственное решение уравнения.
Примеры и сроки
2-IntegerPartitions
Это также работает, но слишком медленно, чтобы удовлетворить требования к скорости.
Range[0, Floor@Sqrt@n]^2
является набором всех квадратов, меньших квадратного корня изn
(максимально возможный квадрат в разбиении).{4}
требует целочисленных разбиений,n
состоящих из 4 элементов из вышеупомянутого набора квадратов.1
, внутри функцииIntegerPartitions
возвращает первое решение.[[1]]
удаляет внешние брекеты; решение было возвращено как набор из одного элемента.3-PowerRepresentations
PowerRepresentations возвращает все решения проблемы 4 квадратов. Это может также решить для сумм других полномочий.
PowersRepresentations возвращает менее чем за 5 секунд 181 способ выражения 123456789 в виде суммы четырех квадратов:
Тем не менее, это слишком медленно для других сумм.
источник
IntegerPartitions
. Как вы можете видеть из времени, скорость сильно варьируется в зависимости от того, близко ли первое (наибольшее) число к квадратному корню изn
. Спасибо за обнаружение нарушения спецификации в более ранней версии.f[805306368]
? Без деления на степени 4 сначала мое решение занимает 0,05 с для 999999999; Я отменил тест для 805306368 через 5 минут ...f[805306368]
возвращается{16384, 16384, 16384}
через 21 минуту. Я использовал {3} вместо {4}. Попытка решить ее с суммой 4 ненулевых квадратов была неудачной после нескольких часов работы.IntegerPartitions[n,4,Range[Floor@Sqrt@n]^2
должно работать тоже. Однако я не думаю, что вам следует использовать метод 1 для оценки, поскольку он не соответствует сроку, указанному в вопросе.Perl -
116 байт87 байт (см. Обновление ниже)Считая Шебанг одним байтом, добавлены новые строки для горизонтального рассудка.
Что-то вроде комбинации код-гольф, подача самого быстрого кода .
Кажется, что средняя (наихудшая?) Сложность случая составляет
O (log n)O (n 0,07 ) . Ничто из того, что я нашел, не работает медленнее, чем 0,001 с, и я проверил весь диапазон от 900000000 до 999999999 . Если вы обнаружите что-либо, что занимает значительно больше времени, ~ 0,1 с или более, пожалуйста, дайте мне знать.Образец использования
Последние два из них, как представляется, являются наихудшими сценариями для других представлений. В обоих случаях показанное решение является буквально самой первой проверенной вещью. Ведь
123456789
это второй.Если вы хотите проверить диапазон значений, вы можете использовать следующий скрипт:
Лучше всего, когда передано в файл. Диапазон
1..1000000
занимает около 14 секунд на моем компьютере (71000 значений в секунду), а диапазон -999000000..1000000000
около 20 секунд (50000 значений в секунду), что соответствует средней сложности O (log n) .Обновить
Редактировать : Оказывается, этот алгоритм очень похож на тот, который использовался ментальными калькуляторами в течение по крайней мере века .
С момента первоначальной публикации я проверил все значения в диапазоне от 1..1000000000 . Поведение «наихудшего случая» было продемонстрировано значением 699731569 , которое проверяло в общей сложности 190 комбинаций, прежде чем прийти к решению. Если вы считаете 190 малой константой - и я, конечно, знаю - поведение наихудшего случая в требуемом диапазоне можно считать O (1) . То есть, так же быстро, как поиск решения с гигантского стола, и в среднем, вполне возможно, быстрее.
Другое дело, хотя. После 190 итераций все, что больше 144400 , даже после первого прохода не вышло . Логика обхода в ширину ничего не стоит - она даже не используется. Приведенный выше код может быть несколько сокращен:
Который выполняет только первый проход поиска. Нам нужно подтвердить, что нет значений ниже 144400, которые требовали бы второго прохода, хотя:
Короче говоря, для диапазона 1..1000000000 существует решение с почти постоянным временем, и вы смотрите на него.
Обновленное обновление
@Dennis и я сделали несколько улучшений этого алгоритма. Вы можете следить за прогрессом в комментариях ниже и последующим обсуждением, если это вас интересует. Среднее число итераций для требуемого диапазона уменьшилось с чуть более 4 до 1,229 , а время, необходимое для проверки всех значений для 1..1000000000 , было увеличено с 18 м 54 с до 2 м 41 с. В худшем случае ранее требовалось 190 итераций; в худшем случае, 854382778 , нужен только 21 .
Окончательный код Python выглядит следующим образом:
При этом используются две предварительно вычисленные таблицы поправок: одна размером 10 КБ, другая - 253 КБ. Приведенный выше код включает функции генератора для этих таблиц, хотя, вероятно, их следует вычислять во время компиляции.
Версию с таблицами коррекции более скромного размера можно найти здесь: http://codepad.org/1ebJC2OV. Эта версия требует в среднем 1,620 итераций в семестр, наихудший случай - 38 , а весь диапазон работает примерно за 3 м 21 с. Немного времени компенсируется, используя побитовое
and
для коррекции b , а не по модулю.улучшения
Четные значения с большей вероятностью дают решение, чем нечетные.
В статье о ментальных вычислениях, связанной с ранее сделанными заметками, отмечается, что если после удаления всех четырех факторов значение, которое нужно разложить, является четным, это значение можно разделить на два, и решение можно восстановить:
Хотя это может иметь смысл для умственного вычисления (меньшие значения, как правило, легче вычислить), это не имеет большого смысла алгоритмически. Если вы возьмете 256 случайных 4- кортежей и изучите сумму квадратов по модулю 8 , вы обнаружите, что значения 1 , 3 , 5 и 7 достигаются в среднем по 32 раза. Однако значения 2 и 6 достигаются по 48 раз. Умножив нечетные значения на 2, вы найдете решение, в среднем, на 33% меньше итераций. Реконструкция заключается в следующем:
Необходимо позаботиться о том, чтобы a и b имели одинаковое соотношение, равно как и c и d , но если решение вообще было найдено, правильное упорядочение гарантировано существует.
Невозможные пути не нужно проверять.
После выбора второго значения b уже может оказаться невозможным существование решения, учитывая возможные квадратичные вычеты для любого заданного модуля. Вместо того, чтобы все равно проверять или переходить к следующей итерации, значение b можно «исправить», уменьшив его на наименьшее значение, которое может привести к решению. В двух таблицах поправок хранятся эти значения: одно для b , а другое для c . Использование более высокого модуля (точнее, использования модуля с относительно меньшим количеством квадратичных остатков) приведет к лучшему улучшению. Значение a не нуждается в коррекции; изменив n на четное, все значенияА действительны.
источник
Питон 3 (177)
После того, как мы уменьшим входное значение,
N
чтобы оно не делилось на 4, оно должно быть выражено в виде суммы четырех квадратов, где один из них является либо наибольшим возможным значением,a=int(N**0.5)
либо одним меньшим, чем, оставляя лишь небольшой остаток для суммы трех других квадратов. заботиться о. Это значительно уменьшает пространство поиска.Вот доказательство позже, этот код всегда находит решение. Мы хотим найти
a
так, чтоn-a^2
это сумма трех квадратов. Из теоремы Лежандра о трех квадратах число представляет собой сумму трех квадратов, если это не форма4^j(8*k+7)
. В частности, такими числами являются либо 0, либо 3 (по модулю 4).Мы показываем, что никакие два последовательных элемента не
a
могут заставить оставшуюся суммуN-a^2
иметь такую форму для обоих последовательных значений. Мы можем сделать это, просто составив таблицуa
иN
по модулю 4, отметив это,N%4!=0
потому что мы извлекли все степени 4 изN
.Поскольку нет двух последовательных
a
уступок(N-a*a)%4 in [0,3]
, один из них является безопасным для использования. Итак, мы жадно используем максимально возможноеn
сn^2<=N
, иn-1
. ПосколькуN<(n+1)^2
остаток, которыйN-a^2
должен быть представлен как сумма трех квадратов, равен не более(n+1)^2 -(n-1)^2
, что равно4*n
. Таким образом, достаточно проверить только значения до2*sqrt(n)
, что в точности соответствует диапазонуR
.Можно было бы дополнительно оптимизировать время выполнения, останавливаясь после одного решения, вычисляя, а не повторяя последнее значение
d
, и выполняя поиск только среди значенийb<=c<=d
. Но даже без этих оптимизаций худший случай, который я смог найти, закончился за 45 секунд на моей машине.Цепочка "для х в R" вызывает сожаление. Вероятно, его можно сократить с помощью подстановки или замены строки путем итерации по одному индексу, который кодирует (a, b, c, d). Импортировать itertools оказалось не стоит.
Изменить: изменено
int(2*n**.5)+1
с,2*int(n**.5)+2
чтобы сделать аргумент чище, то же количество символов.источник
5 => (2, 1, 0, 0)
5 => (2, 1, 0, 0)
запускаю Ideone 3.2.3 или Idle 3.2.2. Что вы получаете?5 => (2, 1, 0, 0)
. Вы даже читали комментарий? (Теперь у нас есть 3 комментария подряд, в которых есть этот фрагмент кода. Можем ли мы продолжать серию?)5 => (2, 1, 0, 0)
, это значит2^2 + 1^2 + 0^2 + 0^2 = 5
. Так что да, мы можем.5 => (2, 1, 0, 0)
это правильно. Примеры в вопросе считают 0 ^ 2 = 0 действительным квадратным числом. Поэтому я интерпретировал (как я думаю, что xnor), что British Color получил что-то еще. Британский цвет, как вы уже не ответили, можем ли мы предположить, что вы на самом деле получаете2,1,0,0
?CJam ,
91907471 байтКомпактный, но медленнее, чем мой другой подход.
Попробуйте онлайн! Вставьте код , введите нужное целое число в поле ввода и нажмите « Выполнить» .
Фон
Этот пост начинался как 99-байтовый ответ GolfScript . Хотя возможности для улучшения еще есть, в GolfScript отсутствует встроенная функция sqrt. Я сохранил версию GolfScript до 5- й версии , так как она была очень похожа на версию CJam.
Однако для оптимизации, начиная с версии 6, требуются операторы, которых нет в GolfScript, поэтому вместо публикации отдельных объяснений для обоих языков я решил отказаться от менее конкурентоспособной (и гораздо более медленной) версии.
Реализованный алгоритм вычисляет числа грубой силой:
Для ввода
m
найдиN
иW
такое чтоm = 4**W * N
.Set
i = 257**2 * floor(sqrt(N/4))
.Set
i = i + 1
.Найти целые числа
j, k, l
такие, чтоi = 257**2 * j + 257 * k + l
, гдеk, l < 257
.Проверьте, если
d = N - j**2 - k**2 - l**2
это идеальный квадрат.Если это не так, вернитесь к шагу 3.
Версия для печати
2**W * j, 2**W * k, 2**W * l, 2**W * sqrt(m)
.Примеры
Сроки соответствуют Intel Core i7-4700MQ.
Как это устроено
источник
С 228
Это основано на алгоритме на странице Википедии, который представляет собой грубую силу O (n).
источник
GolfScript,
133130129 байтовБыстро, но долго. Новая строка может быть удалена.
Попробуйте онлайн. Обратите внимание, что онлайн-переводчик имеет ограничение в 5 секунд, поэтому он может работать не для всех номеров.
Фон
Алгоритм использует теорему Лежандра о трех квадратах , которая утверждает, что каждое натуральное число n , которое не имеет форму
может быть выражена как сумма трех квадратов.
Алгоритм выполняет следующие действия:
Выразите число как
4**i * j
.Найти наибольшее целое число
k
такое, чтоk**2 <= j
иj - k**2
удовлетворяет гипотезе теоремы Лежандра о трех квадратах.Set
i = 0
.Проверьте, если
j - k**2 - (i / 252)**2 - (i % 252)**2
это идеальный квадрат.Если это не так, увеличьте значение
i
и вернитесь к шагу 4.Примеры
Сроки соответствуют Intel Core i7-4700MQ.
Как это устроено
источник
j-k-(i/252)-(i%252)
. Судя по вашим комментариям (я не могу прочитать код), похоже, что вы имеете в видуj-k-(i/252)^2-(i%252)^2
. Кстати, эквивалентj-k-(i/r)^2-(i%r)^2
где r = sqrt (k) может сохранить несколько символов (и, кажется, работает без проблем даже для k = 0 в моей программе на C).j-k^2-(i/252)^2-(i%252)^2
. Я все еще жду, пока ОП уточнит, является ли 0 верным входом или нет. Ваша программа дает1414 -nan 6 4.000000
для ввода0
.0/
=> сбой! : P Я запускаю вашу версию 1 на своем ноутбуке (i7-4700MQ, 8 ГБ ОЗУ). В среднем время выполнения составляет 18,5 секунд.Ред. 1: С, 190
Это еще больше потребляет память, чем версия 0. Тот же принцип: создайте таблицу с положительным значением для всех возможных сумм из 2 квадратов (и ноль для тех чисел, которые не являются суммами из двух квадратов), а затем найдите ее.
В этой версии используйте массив
short
вместо вместо того,char
чтобы хранить попадания, чтобы я мог сохранить корень одного из пары квадратов в таблице, а не просто флаг. Это значительно упрощает функциюp
(для декодирования суммы 2 квадратов), поскольку нет необходимости в цикле.Windows имеет ограничение в 2 ГБ для массивов. Я могу обойти то, с
short s[15<<26]
чем является массив из 1006632960 элементов, достаточно, чтобы соответствовать спецификации. К сожалению, общий размер программы во время выполнения еще более 2 ГБ и (несмотря на настройки параметров ОС) Я не был в состоянии работать над этим размер (хотя теоретически это возможно.) Лучшее , что я могу сделать , этоshort s[14<<26]
(939524096 элементы.)m*m
Должны быть строго меньше этого (30651 ^ 2 = 939483801.) Тем не менее, программа работает отлично и должна работать на любой ОС, которая не имеет этого ограничения.Код без правил
Rev 0 C, 219
Это голодный зверь памяти. Он занимает массив 1 ГБ, вычисляет все возможные суммы из 2 квадратов и сохраняет флаг для каждого в массиве. Затем для пользовательского ввода z он ищет в массиве две суммы из 2 квадратов a и za.
функция
p
затем reconsitutes первоначальные квадраты , которые были использованы , чтобы сделать суммы 2 квадратовa
иz-a
и выводит их, первую из каждой пары в виде целого числа, второй , как двойные (если она есть , чтобы быть все целыми числами , которые необходимы еще два символа,t
>m=t
.)Программа занимает пару минут, чтобы построить таблицу сумм квадратов (я думаю, что это связано с проблемами управления памятью, я вижу, что выделение памяти увеличивается медленно, а не подпрыгивает, как можно было ожидать). Однако, как только это будет сделано выдает ответы очень быстро (если нужно рассчитать несколько чисел, программа
scanf
может быть зациклена).Негольфированный код
Пример вывода
Первый вопрос. Второй был выбран как трудный для поиска. В этом случае программа должна выполнить поиск до 8192 ^ 2 + 8192 ^ 2 = 134217728, но это займет всего несколько секунд после создания таблицы.
источник
#include <stdio.h>
(для scanf / printf) или#include <math.h>
(для sqrt.) компилятор связывает необходимые библиотеки автоматически. Я должен поблагодарить Денниса за это (он сказал мне по этому вопросу codegolf.stackexchange.com/a/26330/15599 ) Лучший совет по гольфу, который у меня когда-либо был.include
. Для компиляции в Linux вам нужен флаг-lm
stdio
и несколько других библиотек, но неmath
даже сinclude
? Под чем я понимаю, если вы установите флаг компилятора, вам всеinclude
равно не нужно ? Ну, это работает для меня, так что я не жалуюсь, еще раз спасибо за совет. Кстати, я надеюсь опубликовать совершенно другой ответ, используя теорему Лежандра (но она все равно будет использоватьsqrt
.)-lm
влияет на компоновщик, а не на компилятор.gcc
предпочитает не требовать прототипов для функций, которые он «знает», поэтому он работает с включениями или без них. Однако заголовочные файлы предоставляют только прототипы функций, а не сами функции. В Linux (но не в Windows, по-видимому) libm математической библиотеки не является частью стандартных библиотек, поэтому вы должны указатьld
ссылку на нее.Mathematica, 138 символовТаким образом, получается, что это приводит к отрицательным и мнимым результатам для определенных входных данных, как указано в edc65 (например, 805306368), так что это не является правильным решением. Я оставлю это пока, и, возможно, если я действительно ненавижу свое время, я вернусь и попытаюсь это исправить.
Или непокоренный
Я не слишком внимательно смотрел на алгоритмы, но я ожидаю, что это та же идея. Я просто придумал очевидное решение и подправил его, пока оно не сработало. Я проверил это для всех чисел от 1 до одного миллиарда, и ... это работает. Тест занимает около 100 секунд на моей машине.
Приятный момент в том, что, поскольку b, c и d определены с отложенными присваиваниями
:=
, их не нужно переопределять при уменьшении a. Это сохранило несколько дополнительных строк, которые у меня были раньше. Я мог бы поиграть в гольф дальше и вложить лишние части, но вот первый проект.О, и вы запускаете его как,
S@123456789
и вы можете проверить это с помощью{S@#, Total[(S@#)^2]} & @ 123456789
или# == Total[(S@#)^2]&[123456789]
. Исчерпывающий тестРаньше я использовал оператор Print [], но это сильно замедляло его, хотя он никогда не вызывался. Пойди разберись.
источник
n - a^2 - b^2 - c^2
как переменную и проверить, чтоd^2
она равна.a * 4^(2^k)
дляk>=2
извлечения всех степеней 4, так чтоa
это не кратно 4 (но может быть четным). Более того, у каждогоa
либо 3 мода 4, либо вдвое больше такого числа. Самый маленький - 192.Haskell 123 + 3 = 126
Простая грубая сила по заранее рассчитанным квадратам.
Он нуждается в
-O
опции компиляции (я добавил 3 символов для этого). Для худшего случая 999950883 требуется менее 1 минуты.Только проверено на GHC.
источник
C: 198 символовЯ, вероятно, могу сжать его до чуть более 100 символов. Что мне нравится в этом решении, так это минимальное количество мусора, просто цикл for, делающий то, что должен делать цикл for (что должно быть сумасшедшим).
И сильно претенциозно:
Изменить: Это не достаточно быстро для всех ввода, но я вернусь с другим решением. Я оставлю этот троичный беспорядок на месте.
источник
Rev B: C, 179
Спасибо @Dennis за улучшения. Остальная часть ответа ниже не обновляется с версии А.
Ред. А: С, 195
Гораздо быстрее, чем мой другой ответ и с гораздо меньшим количеством памяти!
Для этого используется http://en.wikipedia.org/wiki/Legendre%27s_three-square_theorem . Любое число не следующей формы может быть выражено как сумма 3 квадратов (я называю это запрещенной формой):
4^a*(8b+7), or equivalently 4^a*(8b-1)
Обратите внимание, что все нечетные квадратные числа имеют форму,
(8b+1)
а все четные квадратные числа имеют внешнюю форму4b
. Однако это скрывает тот факт, что все четные квадратные числа имеют форму4^a*(odd square)==4^a*(8b+1)
. В результате2^x-(any square number < 2^(x-1))
для нечетногоx
всегда будет иметь запрещенную форму. Следовательно, эти числа и их кратные являются сложными случаями, поэтому многие программы здесь делят степени 4 в качестве первого шага.Как указано в ответе @ xnor,
N-a*a
нельзя использовать запрещенную форму для двух последовательных значенийa
. Ниже я представлю упрощенную форму своей таблицы. В дополнение к тому факту, что после деления на 4N%4
не может быть равен 0, обратите внимание, что есть только 2 возможных значения для(a*a)%4
.Итак, мы хотим избежать значений,
(N-a*a)
которые могут иметь запрещенную форму, а именно те, где(N-a*a)%4
3 или 0. Как можно видеть, это не может происходить для одного и того жеN
с нечетным и четным(a*a)
.Итак, мой алгоритм работает так:
Мне особенно нравится способ, которым я делаю шаг 3. Я добавляю 3 к
N
, так что декремент необходим, если(3+N-a*a)%4 =
3 или 2. (но не 1 или 0.) Разделите это на 2, и вся работа может быть выполнена довольно простым выражением ,Код без правил
Обратите внимание на один
for
циклq
и использование деления / по модулю для получения значенийb
иc
из него. Я пытался использоватьa
в качестве делителя вместо 256 для сохранения байтов, но иногда значениеa
было неправильным, и программа зависала, возможно, на неопределенный срок. 256 был лучшим компромиссом, который я могу использовать>>8
вместо/256
деления.Выход
Интересно, что если вы введете квадратное число,
N-(a*a)
= 0. Но программа обнаруживает, что0%4
= 0 и уменьшается до следующего квадрата вниз. В результате входные данные квадрата всегда разбиваются на группу меньших квадратов, если они не имеют форму4^x
.источник
m=1
раньшеmain
. 2. Выполнитьscanf
вfor
выписке. 3. Используйтеfloat
вместоdouble
. 4.n%4<1
короче чем!(n%4)
. 5. В строке формата printf есть устаревшее место.n-=a*a
не работает, потому чтоa
может быть изменен впоследствии (он дает некоторые неправильные ответы и зависает в небольшом количестве случаев, например, 100 + 7 = 107). Я включил все остальное. Было бы неплохо что-то сократить,printf
но я думаю, что единственный ответ - это сменить язык. Ключ к скорости заключается в том, чтобыa
быстро найти хорошее соотношение цены и качества . Написанная на C и имеющая пространство поиска менее 256 ^ 2, это, пожалуй, самая быстрая программа здесь.printf
оператора кажется трудным без использования макроса или массива, который увеличит объем в другом месте. Смена языков кажется «простым» способом. Ваш подход будет весить 82 байта в CJam.JavaScript -
175 191 176173 символовГрубая сила, но быстро.
Редактировать быстро, но недостаточно для какого-то неприятного ввода. Я должен был добавить первый шаг сокращения умножением на 4.
Редактировать 2 Избавиться от функции, вывод внутри цикла, затем принудительно завершить работу
Редактировать 3 0 неверный ввод
Ungolfed:
Пример вывода
источник