Это число Лошиана?


33

Положительное целое число k- это число Леша, если

  • kможет быть выражен как i*i + j*j + i*jдля i, jцелых чисел.

Например, первые положительные числа Леша: 1( i=1, j=0); 3( i=j=1); 4( i=2, j=0); 7( i=2, j=1); 9( i=-3, j=3); ... Обратите внимание , что i, jдля данных kне являются уникальными. Например, 9также могут быть получены с i=3, j=0.

Другие эквивалентные характеристики этих чисел:

  • kможет быть выраженно как i*i + j*j + i*jдля i, jнеотрицательных целых чисел. (Для каждой пары целых чисел i, jесть пара неотрицательных целых чисел , которое дает то же k)

  • Существует ряд kсмежных шестиугольников, которые образуют тесселяцию на шестиугольной сетке (см. Иллюстрации для k = 4и для k = 7). (Благодаря этому свойству эти номера находят применение в сетях мобильной сотовой связи .)

  • Смотрите больше характеристик на странице OEIS последовательности.

Соревнование

Если задано положительное целое число , выведите правдивый результат, если это число Лошиана , или ложный результат в противном случае.

Программа или функция должна обрабатывать (скажем, менее чем за минуту) входные данные вплоть до 1000или до ограничений типа данных.

Код гольф. Кратчайшие победы.

Контрольные примеры

Следующие числа должны вывести достоверный результат:

1, 4, 7, 12, 13, 108, 109, 192, 516, 999

Следующие числа должны вывести ложный результат:

2, 5, 10, 42, 101, 102, 128, 150, 501, 1000

Связанный (как отмечено @PeterTaylor)
Луис Мендо

Примечание для алгоритма перебора: если вы выполняете итерацию до √k, вы уменьшаете сложность алгоритма с O (n²) до O (n) за счет некоторых байтов c;
Род

i, j non-negative integersили 9 (i=-3, j=3)- какой это?
Тит

1
@ Титус О, теперь я вижу. Для каждой пары целых чисел i, j есть неотрицательная пара, которая дает одинаковое k
Луис Мендо

Ответы:


17

Желе , 11 9 байт

ÆF‘%3,2ḄȦ

Попробуйте онлайн! или проверьте все контрольные примеры .

Задний план

В Элементарных результатах о бинарной квадратичной форме a² + ab + b² автор доказывает следующую теорему о числах Лёшиана.

Теорема 16. Необходимым и достаточным условием того, чтобы любое неотрицательное целое число было в форме a² + ab + b² , было бы то, что при его простой факторизации все простые числа, кроме 3 , которые не находятся в форме (6k + 1), имеют четное экспонент.

Как отмечено на соответствующей странице OEIS , поскольку все целые числа являются конгруэнтными 0 , 1 или 2 по модулю 3 , число 3 является единственным простым числом , которое конгруэнтно 0 , и все числа формы (6k + 1) являются конгруэнтными 1 , теорема может быть сформулирована альтернативно следующим образом.

Неотрицательное целое число n является лёшевым числом тогда и только тогда, когда все простые множители n , конгруэнтные 2 по модулю 3, имеют четные показатели.

Как это работает

ÆF‘%3,2ḄȦ  Main link. Argument: n (integer)

ÆF         Yield the prime factorization of n, as prime-exponent pairs.
  ‘        Increment all primes and exponents, turning primes of the form 3k - 2
           into multiples of 3 and odd exponents into multiples of 2.
   %3,2    Reduce all incremented primes/exponents modulo 3/2.
           n is Löschian if and only if this does not result in a [0, 0] pair.
           Due to Jelly's form of vectorization, this yields [3, 2] if n = 1.
       Ḅ   Unbinary; convert each pair from base 2 to integer.
           Note that [x, y] = [0, 0] if and only if 2x + y = 0.
        Ȧ  All; return 1 if the result contains no zeroes, 0 otherwise.

17

Retina , 66 63 45 43 36 байт

^()(\1(?<1>.\1))+(\1(.(?(4).\4)))*$

Несмотря на заголовок «Retina», это просто обычное регулярное выражение .NET, которое принимает унарные представления чисел Лоше.

Входы 999 и 1000 занимают меньше секунды.

Попробуйте онлайн! (Первая строка включает набор тестов, разделенных переводом строки, а следующие две для удобства занимаются преобразованием в унарный.)

объяснение

Решение основано на классификации, согласно которой входные данные могут быть записаны как i*i + j*(i + j)положительные iи неотрицательные j(поскольку нам не нужно обрабатывать ввод 0), и это n*nвсего лишь сумма первых nнечетных целых чисел. Игра в гольф была интересным упражнением в прямом обращении.

«Прямая ссылка» - это когда вы помещаете обратную ссылку в группу, к которой она относится. Конечно, это не работает, когда группа используется в первый раз, так как обратная ссылка еще не на что, но если вы поместите это в цикл, то обратная ссылка каждый раз получает перехват предыдущей итерации. Это, в свою очередь, позволит вам создавать больший захват с каждой итерацией. Это может быть использовано для создания очень компактных моделей для таких вещей, как треугольные числа, квадраты и числа Фибоначчи.

В качестве примера, используя тот факт, что квадраты являются просто суммами первых nнечетных целых чисел, мы можем сопоставить квадратные данные следующим образом:

(^.|..\1)+$

На первой итерации ..\1не может работать, потому что \1еще не имеет значения. Итак, мы начнем с ^.захвата одного персонажа в группу 1. На последующих итерациях ^.больше не совпадает из-за привязки, но теперь ..\1действует. Он соответствует на два символа больше, чем в предыдущей итерации, и обновляет захват. Таким образом, мы сопоставляем увеличивающиеся нечетные числа, получая квадрат после каждой итерации.

К сожалению, сейчас мы не можем использовать эту технику как есть. После сопоставления i*iнам нужно получить iтакже, чтобы мы могли умножить его на j. Простой (но долгий) способ сделать это состоит в том, чтобы использовать тот факт, что сопоставление i*iтребует iитераций, поэтому мы собираем данные iв группе 1. Теперь мы могли бы использовать балансировочные группы, чтобы извлечь это i, но, как я сказал, это дорого.

Вместо этого я нашел другой способ записать эту «сумму последовательных нечетных целых чисел», которая также дает iв конце группу захвата. Конечно, iнечетное число просто 2i-1. Это дает нам возможность увеличивать прямую ссылку только на 1 на каждой итерации. Вот эта часть:

^()(\1(?<1>.\1))+

Это ()просто помещает пустой захват в группу 1(инициализируя iв 0). Это в значительной степени эквивалентно ^.|приведенному выше простому решению, но использование |в этом случае будет немного сложнее.

Тогда у нас есть основной цикл (\1(?<1>.\1)). \1соответствует предыдущему i, (?<1>.\1)затем обновляет группу 1с помощью i+1. Что касается нового i , мы только что подобрали 2i-1персонажей. Именно то, что нам нужно.

Когда мы закончим, мы сопоставим некоторый квадрат, i*iи группа 1все еще содержит iсимволы.

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

(.(?(4).\1))*

Это в основном то же самое (^.|..\4)*, за исключением того, что мы не можем использовать, ^потому что мы не в начале строки. Вместо этого мы используем условное, чтобы сопоставить дополнительное .\1только тогда, когда мы уже использовали группу 4. Но на самом деле это точно так же. Это дает нам j*j.

Единственное, чего не хватает, это j*iтермин. Мы комбинируем это с j*jиспользованием факта, что j*jвычисления все еще требуют jитераций. Таким образом , для каждой итерации мы также продвигать курсор iс \1. Нам просто нужно убедиться, что не записать это в группу 4, потому что это будет мешать совпадению последовательных нечетных чисел. Вот как мы приходим к:

(\1(.(?(4).\1)))*

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

@JavierDiaz Существует ряд публикаций, объясняющих прямые ссылки на переполнение стека, основанные на регулярном выражении Java. Примеры там, вероятно, немного проще.
Мартин Эндер

13

CJam ( 16 15 байт)

{mF{~\3%2=&},!}

Онлайн демо

Это блок ( «анонимные функции») , который принимает данные в стеке и листьев 0или 1в стеке. Он использует характеристику, что число является лешиановским, если оно не имеет простого множителя, равного 2 mod 3 с нечетной кратностью.

Спасибо Деннису за однобайтовую экономию.


Вау, хорошая характеристика!
Луис Мендо


6

Haskell, 42 байта

f k=or[k==i*i+j*j+i*j|i<-[0..k],j<-[0..i]]

Пример использования: f 501-> False.

Старается все комбинации iот 0до kи jот 0до i. orвозвращает, Trueесли равенство k==i*i+j*j+i*jвыполнено хотя бы для одной из комбинаций.

@flawr нашел немного другую версию с тем же количеством байтов:

f k|v<-[0..k]=or[(i+j)^2==k+i*j|i<-v,j<-v]

Я не знал о or, круто =) Может быть , у вас есть идея , как гольфы этой альтернативной формулировка: f k|v<-[0..k]=or[(i+j)^2==k+i*j|i<-v,j<-v]?
flawr

@ Flawr: нет, не знаю, как продвигать свою версию дальше. Если вы не возражаете, я добавлю его в свой ответ в качестве альтернативной версии.
Ними

5

Java 8, 81 байт

k->{for(int i=0,j;i<=k;i++)for(j=0;j<=k;)if(i*i+j*j+i*j++==k)return 1;return 0;};

простая, наивная реализация. по совпадению тот же код, что и в C #, но использует ->вместо =>.


На три байта меньше, потому что вы можете опустить фигурные скобки и окончание ;. ЧЕРТ!
TheLethalCoder

@TheLethalCoder Я на самом деле не могу, я сделал ошибку - такое же количество байтов, как C #.
Джастин

В любом случае, я чувствую себя лучше :)
TheLethalCoder

Это не похоже на отрицательный iили j.
Тит


4

Желе , 15 14 13 12 байт

1 байт благодаря милям.

²S+P
‘ṗ2’Ç€i

Попробуйте онлайн!

Проверьте меньшие тестовые случаи .

Совет при тестировании большого количества (больше 50): не надо.

Истина - это положительное число. Фолси ноль.

объяснение

‘ṗ2’Ç€i   main chain, argument: z
‘ṗ2’      generate all pairs of numbers between 0 and z inclusive
    ǀ    apply the helper link to each pair
      i   find the index of z in the result

²S+P   helper link, argument: [x,y] (a pair of numbers)
²      compute [x*x, y*y]
 S     x*x+y*y
  +P   x*x+y*y+x*y

Связали (пока) ... :-)
Луис Мендо

Должны ли мы использовать характеристику Петра ...?
Луис Мендо

@LuisMendo Это кажется интересным, но кажется, что это будет дольше
Leaky Nun

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

@ Майлз Это умно, спасибо.
Утренняя монахиня


3

MATL , 14 13 байт

t:0hU&+HM&*+m

Попробуйте онлайн! Или проверьте все тестовые случаи .

Выходы 1или 0.

объяснение

t:    % Implicitly input number k. Duplicate. Generate vector [1 2 ...k]
0h    % Concatenate a 0. Gives [1 2 ... k 0]
U     % Square, element-wise. Gives [1 4 ... k^2 0]
&+    % Sum of all pairs from this vector. Gives a (k+1)×(k+1) matrix
HM    % Push [1 2 ... k 0] again
&*    % Product of all pairs from this vector. Gives a (k+1)×(k+1) matrix
+     % Add the two matrices
m     % True if k is a member of the resulting matrix. Implicitly display

Ты только что вышел из гольфа, Джелли?
Утренняя монахиня

@LeakyNun Давайте посмотрим, как долго это длится. Может быть, я немного задержу объяснение кода :-P
Луис Мендо

Нет. - - - - -
Дрянная Монахиня

Твоя очередь - - -
Утренняя монахиня

@LeakyNun Aw :-( Теперь я могу добавить объяснение :-)
Луис Мендо

3

Python, 49 байт

lambda n:0in[(n-3*i*i+0j)**.5%1for i in range(n)]

Использует эквивалентную квадратичную форму, заданную на OEIS of n == 3*i*i+j*j. Проверьте, n-3*i*iявляется ли квадрат идеальным для любого i, взяв его квадратный корень и проверив, является ли оно целым числом, т. Е. Равно 0 по модулю 1. Обратите внимание, что Python точно вычисляет квадратные корни из идеальных квадратов без ошибки с плавающей запятой. Это +0jделает его комплексным числом, чтобы избежать ошибки в квадратном корне из отрицания.


3

C (gcc), 71 69 байт

i,j,r;f(n){for(r=i=n+1;i--;)for(j=n;j--;)r*=n!=i*i+j*j+i*j;return!r;}

69 байт: i,j,r;f(n){for(r=i=n+1;i--;)for(j=n;j--;)r*=n!=i*i+j*j+i*j;return!r;}.
owacoder

Это не похоже на отрицательный iили j.
Тит

@ Титус Вопрос диктует неотрицательно iи j.
orlp

положительный k, но не iа j. Присмотритесь к примерам.
Тит

@ Цитата цитата из задачи: « kможет быть выражено как i*i + j*j + i*jдля i, j неотрицательных целых чисел». Вы присмотритесь.
orlp

2

C #, 84 82 81 байт

k=>{for(int i=0,j;i<=k;++i)for(j=0;j<=k;)if(i*i+j*j+i*j++==k)return 1;return 0;};

Наивное решение. 1 = правда, 0 = ложь


2

VBA, 68 67 байт

Function L(N):For a=0To N:For b=0To a:L=L+(N=a^2+a*b+b^2):Next b,a

Наивный поиск, начинающий слегка замедляться при n = 1000. Excel распознает нулевой возврат как ложный, а все остальные возвращается как правдивый.

Обратите внимание, что исследование отрицательных значений i и j не требуется, поскольку дано i> j> = 0 :

(-i) 2 + (-i) (- j) + (-j) 2 = i 2 + ij + j 2

(тот же результат, что и для i и j )

(-i) 2 + (-i) j + j 2 = i 2 - ij + j 2

i 2 + i (-j) + (-j) 2 = i 2 - ij + j 2

(если один отрицательный, не имеет значения, какой), а затем

(ij) 2 + (ij) j + j 2 = (i 2 - 2ij + j 2 ) + (ij - j 2 ) + j 2 = i 2 - ij + j 2

И поскольку оба (ij) и j неотрицательны, любое поколение чисел Леша с отрицательным числом может быть достигнуто с использованием неотрицательных чисел.


Сохраненный байт, Next:Next-> Next b,aблагодаря Тейлор Скотт.


Это не похоже на отрицательный iили j.
Тит

См. Первый пункт в разделе «Другие эквивалентные характеристики». Обратите внимание, что все тесты подходят правильно. Я добавлю математическое обоснование к своему ответу (если смогу).
Джоффан

Извини, я виноват. Переоценивать это не нужно.
Тит

@Joffan вы можете конденсироваться Next:NextвNext b,a
Тейлор Скотт

@ Джоффан снова смотрит на ваше решение, может быть, это из-за отсутствия :End Functionв конце вашего решения
Тейлор Скотт

1

Javascript (с использованием внешней библиотеки - Enumerable) (63 байта)

k=>_.Range(0,k+1).Any(i=>_.Range(0,k+1).Any(j=>i*i+j*j+i*j==k))

Ссылка на библиотеку: https://github.com/mvegh1/Enumerable Объяснение кода: создайте диапазон целых чисел от 0 до k (назовите его диапазоном «i») и проверьте, удовлетворяет ли какой-либо «i» определенному предикату. Этот предикат создает диапазон от 0 до k (назовите его диапазоном «j») и проверяет, удовлетворяет ли какой-либо «j» определенному предикату. Этот предикат является формулой Лоше

введите описание изображения здесь


1

Perl 6 ,  52 51  50 байт

->\k{?first ->(\i,\j){k==i*i+j*j+i*j},(0..k X 0..k)}
->\k{?grep ->(\i,\j){k==i*i+j*j+i*j},(0..k X 0..k)}

{?grep ->(\i,\j){$_==i*i+j*j+i*j},(0..$_ X 0..$_)}

Объяснение:

{
  # Turn the following into a Bool
  # ( Technically not necessary as a list of 1 or more values is truthy )
  ?

  # find all where the code block returns a truthy value
  grep

  # pointy block that takes one value (list of 2 values)
  # and gives each of the values in it a name
  ->
    $ ( \i, \j )
  {
    # return true if the definition matches
    $_ == i*i + j*j + i*j
  },

  # a list of 2 element lists (possible i and j values)
  ( 0..$_ X 0..$_ )
}

Тест:

use v6.c;
use Test;

my @true = 0, 1, 4, 7, 12, 13, 108, 109, 192, 516, 999;
my @false = 2, 5, 10, 42, 101, 102, 128, 150, 501, 1000;

plan (@true + @false) * 2;

my &is-loeschian = {?grep ->(\i,\j){$_==i*i+j*j+i*j},(0..$_ X 0..$_)}

for |(@true X True), |(@false X False) -> ( $input, $expected ) {
  my ($result,$seconds) = $input.&time-it;
  is $result, $expected, ~$input;
  cmp-ok $seconds, &[<], 60, "in $seconds seconds"
}

sub time-it ( $input ) {
  my $start = now;
  my $result = $input.&is-loeschian;
  my $finish = now;
  return ( $result, $finish - $start )
}
1..42
ok 1 - 0
ok 2 - in 0.00111763 seconds
ok 3 - 1
ok 4 - in 0.00076766 seconds
...
ok 19 - 516
ok 20 - in 0.19629727 seconds
ok 21 - 999
ok 22 - in 0.1126715 seconds
ok 23 - 2
ok 24 - in 0.0013301 seconds
ok 25 - 5
ok 26 - in 0.00186610 seconds
...
ok 37 - 150
ok 38 - in 0.83877554 seconds
ok 39 - 501
ok 40 - in 9.2968558 seconds
ok 41 - 1000
ok 42 - in 37.31434146 seconds

Это не похоже на отрицательный iили j.
Тит

@Titus (0..$_ X 0..$_)производит пустой список , если $_меньше 0, поэтому нет необходимости проверять негатив iи jпотому , что они никогда не будут отрицательными. Так как предполагается, что он работает только Trueдля положительного числа Леша, мне не нужно делать ничего особенного для отрицательного случая.
Брэд Гилберт b2gills

9 = (3*3)+(-3*-3)+(3*-3)является положительным по Loeschian i=3, j=-3; НО я перечитал, что у каждого числа Леша есть неотрицательные iи j. Поэтому искать отрицательные числа не обязательно. Так что на самом деле мы могли бы удалить эти комментарии. Извините за ошибки; моя вина.
Тит

@Titus, модифицирующий код для получения {grep ->(\i,\j){$_==i*i+j*j+i*j},(-$_..$_ X -$_..$_)}(9)результата ((-3,0),(-3,3),(0,-3),(0,3),(3,-3),(3,0)). Честно говоря, я, вероятно, просто адаптировал это из других ответов.
Брэд Гилберт b2gills

1

PowerShell v2 +, 63 56 55 байт

param($k)(0..$k|%{0..($i=$_)|%{$i*($i+$_)+$_*$_}})-eq$k

Принимает ввод $k, повторяет цикл дважды (внешний цикл $i = 0 to $k, внутренний цикл $j = 0 to $i), каждая итерация генерирует результат i*i + j*j + i*j(сокращенный до i*(i+j) + j*j). Эти результаты инкапсулируются в паренах и передаются в виде массива -eq$k. Это действует как фильтр для выбора только элементов, которые равны входным данным. Выводит ненулевое значение (число назад) для truey или ничего (пусто) для falsey. Процессы 1000примерно за 15 секунд на моей машине.

Тестовые случаи

PS C:\Tools\Scripts\golfing> (1,4,7,12,13,108,109,192,516,999|%{.\loeschian-numbers.ps1 $_})-join','
1,4,7,12,13,108,109,192,516,999

PS C:\Tools\Scripts\golfing> (2,5,10,42,101,102,128,150,501,1000|%{.\loeschian-numbers.ps1 $_})-join','

PS C:\Tools\Scripts\golfing>

1

Perl, 54 + 1 ( -nфлаг) = 55 байт

for$i(0..$_){for$j(0..$_){$i*$i+$j*$j+$i*$j-$_?1:say}}

Необходимо -nи -M5.010флаги для запуска:

perl -nE 'for$i(0..$_){for$j(0..$_){$i*$i+$j*$j+$i*$j-$_?1:say}}'

Выводит некоторые данные, если число является числом Леша, и ничего другого.

Эта реализация довольно скучна, поэтому вот еще одна, для 87 байтов, на основе регулярных выражений, просто для глаз:

perl -pE '$_=(1 x$_)=~/^(.*)(??{$1x(-1+length$1)})(.*)(??{$2x(-1+length$2)})(??{$1x length$2})$/'

Осторожнее с этим, так как при возврате будет много памяти, поэтому не пытайтесь проверять слишком большие числа! (особенно числа, которые не Loeschians)


1

Дьялог АПЛ , 19 байт

⊢∊(∘.(×-⍨2*⍨+)⍨0,⍳)

Проверяет, если k ∊ ( i + j ) ² - ij , для любых 0 ≤ i , jk .

    является k
членом
    ∘.всех комбинаций
        × i времен j,
        -⍨ вычтенных из
        2*⍨квадрата
        + i плюс j
     для всех i и j в
    0,нуле с добавлением
    целых чисел от 1 до k

1000 занимает 3,3 секунды на моем M540 и даже меньше на TryAPL .


1

Matlab, 53 52 байта

n=input('');[a b]=ndgrid(0:n);find((a+b).^2-a.*b==n)

Простой поиск по всем возможностям.
Выводит пустой массив как ложное значение, а непустой вектор - как истинное значение.

Рассматривая матрицу из всех нулей как ложную, а матрицу не из всех нулей как правдивую, мы можем избавиться от findфункции, результатом которой является решение 47 46 байт :

n=input('');[a b]=ndgrid(0:n);(a+b).^2-a.*b==n

Один байт сохранен благодаря @flawr


1
(a+b).^2-a.*b==nкороче
flawr


1

Mathematica, 44 байта

MemberQ[(+##)^2-##&@@@0~Range~#~Tuples~2,#]&

Безымянная функция, принимающая целое число в качестве входных данных и возвращающая Trueили False. Команда 0~Range~#~Tuples~2создает все упорядоченные пары целых чисел как между 0входом, так и между ним #. Функция (+##)^2-##&вычисляет квадрат суммы своих аргументов минус произведение своих аргументов; при вызове двух аргументов, iи jэто точно так, i^2+j^2+ijкак хотелось бы. Таким образом, эта функция вызывается для всех кортежей, а затем MemberQ[...,#]проверяет, является ли ввод одним из результирующих значений.


1

ASP, 39 + 4 = 43 байта

o:-k=I*I+J*J+I*J;I=1..k;J=1..k.:-not o.

Вывод: задача выполнима тогда и только тогда, когда k является лёшевым.

Программирование набора ответов - это логический язык, похожий на пролог. Я использую здесь реализацию Potassco , clingo .

Ввод берется из параметров ( -ck=длиной 4 байта). Пример звонка:

clingo -ck=999

Выходной образец:

SATISFIABLE

Пробовал с 1000:

clingo -ck=1000

Выходной образец:

UNSATISFIABLE

Вы можете попробовать это в своем браузере ; К сожалению, этот метод не обрабатывает флаги вызова, поэтому вам нужно добавить строку #const k=999, чтобы он работал.


Ungolfed & объяснил код:

v(1..k).  % predicate v(X) holds for any X in [1..k]
o:- k=I*I+J*J+I*J ; v(I) ; v(J).  % o holds if k is Loeschian.
:- not o.  % discard models where o doesn't holds (make problem unsatisfiable)

1

PHP, 70 байт

for(;$i++<$k=$argv[1];)for($j=$i+1;$j--;)$i*$i+$j*$j+$i*$j-$k?:die(1);

принимает входные данные из аргумента командной строки; выходит с 1по номеру Лёшского, с 0остальным.
Беги с -nr.

сломать

for(;$i++<$k=$argv[1];)     # loop $i from 1 to $k
    for($j=$i+1;$j--;)      # loop $j from $i to 0
        $i*$i+$j*$j+$i*$j-$k?   # if $i,$j,$k do not satisfy the equation, do nothing
        :die(1);                # else exit with return code 1
                            # implicit: exit with code 0
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.