Послідовність занадто мета


25

Почнемо з порожньої 1-індексованої послідовності:

_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,...

На n- му кроці ми заповнюємо кожну a (n) пробіли цілими числами, більшими за 1, починаючи з першого залишкового порожнього, де a (n) - n- й запис у послідовності.

Після першого кроку:

2,_,3,_,4,_,5,_,6,_,7,_,8,_,9,_,10,_,11,_,12,_,13,_,...

Зауважте, що (1) має бути 2, оскільки перше ціле число, що перевищує 1, дорівнює 2.

На другому кроці ми заповнюємо кожну (2) заготовку. Очевидно, що (2) має бути 2.

2,2,3,_,4,3,5,_,6,4,7,_,8,5,9,_,10,6,11,_,12,7,13,_,...

На третьому кроці ми заповнюємо кожну (3) заготовку. З послідовності a (3) = 3.

2,2,3,2,4,3,5,_,6,4,7,_,8,5,9,3,10,6,11,_,12,7,13,_,...

На четвертому кроці ми заповнюємо кожну (4) заготовку. З послідовності a (4) = 2.

2,2,3,2,4,3,5,2,6,4,7,_,8,5,9,3,10,6,11,3,12,7,13,_,...

Врешті-решт:

2,2,3,2,4,3,5,2,6,4,7,2,8,5,9,3,10,6,11,3,12,7,13,2,...

Завдання

Дано n, поверніть n- й елемент послідовності.

Перші 10000000000 терміни послідовності можна знайти тут .

Це . Найкоротша відповідь у байтах виграє. Застосовуються стандартні лазівки .


@LuisMendo Спасибі, я додав його.
Лина монашка

Просто цікаво, що не так, щоб mr.One був виключений із послідовності?
Мертвий Поссум

@DeadPossum добре, якщо ви заповнюєте кожну порожню, то ви все зробите в один крок.
Leaky Nun

2
@DeadPossum Якщо a (n) дорівнює 1, то n-й крок заповнить усі залишки порожнього, завершуючи генерацію.
Leaky Nun

1
@QBrute Я надав перелік перших 100000000, пов'язаних у питанні; просто побудувати їх.
Лина монашка

Відповіді:


20

Haskell , 80 67 байт

g~(a:b)|let k!l=k:take(a-1)l++(k+1)!drop(a-1)l=2!g b
m=g m
(!!)$0:m

Спробуйте в Інтернеті!

Haskell - ідеальна мова для визначення нескінченного списку з точки зору самого себе.


1
Зважаючи на те, що посилання TIO працює, як очікувалося, я думаю, що моє запитання замість цього має бути: Чи можете ви додати пояснення, як це працює?
Джуліан Вольф

2
@JulianWolf Це здається, що вам незнайомі letохоронці зразків. pattern1 | let pattern2 = expr2 = expr1означає те саме, що pattern1 = let pattern2 = expr2 in expr1(з тієї ж причини, що [expr1 | let pattern2 = expr2]означає те саме, що і [let pattern2 = expr2 in expr1]).
Anders Kaseorg

1
Мені потрібно пам’ятати letохоронців шаблонів (особливо, що вони можуть виконувати функції)! Також m=2:2:2`drop`g mбайт коротший.
Ørjan Johansen

1
(!!)$0:mна два байти коротше.
Ørjan Johansen

1
Насправді ви можете 2:2:повністю скинути речі з трохи більшою лінню: g ~(a:b)|...і m=g m.
Ørjan Johansen

10

C, 123 байти

f(n){int*p=calloc(n,4),i=0,j,k;for(*p=p[1]=2;i<n;++i)for(j=0,k=i/2?0:2-i;j<n;++j)p[j]||k++%p[i]||(p[j]=k/p[i]+2);n=p[n-1];}

Спробуйте в Інтернеті!

Покрокова інструкція

f(n){int*p=calloc(n,4),

Виділіть масив з n цілих чисел для зберігання перших n елементів послідовності. Це жорсткі коди sizeof(int)як 4, що є безпечним припущенням у більшості випадків і, безумовно, те, що я готовий зробити в контексті кодового гольфу. :)

i=0,j,k;

Це всі лічильники: iдля індексу кроку, який ми робимо, jпровести цикл через послідовність пошуку порожніх пробілів і kпідрахувати, скільки порожніх пробілів було проглянуто.

for(*p=p[1]=2;i<n;++i)

Перш ніж почати наш основний цикл, ми пробираємося в ініціалізації перших двох елементів послідовності до 2. ( p[0]= *(p + 0)= *p.) Це k, однак, знімає кількість рахунків для , хоча, але ...

for(j=0,k=i/2?0:2-i;j<n;++j)

... ми також робимо приховану ініціалізацію k, яка перевіряє, чи iне менше, 2і виправляє початкове значення, kякщо так. Тут також починається внутрішня петля, яка повторюється протягом усієї послідовності, поки що під час кожного кроку.

p[j]||k++%p[i]||(p[j]=k/p[i]+2);

Цей рядок дійсно може використовувати деякі пояснення. Ми можемо розширити це до:

if (!(p[j] || ((k++) % p[i]))) {
    p[j] = k / p[i] + 2;
}

шляхом короткого замикання, а потім законами Де Моргана і 0фальшивим в С:

if (p[j] == 0 && ((k++) % p[i]) == 0) {
    p[j] = k / p[i] + 2;
}

По суті, це говорить: "якщо цей простір порожній, приріст k. І якщо kраніше було кратним розміру кроків, запустіть наступне твердження." Отже, ми запускаємо оператор з елементами кожного розміру кроку , саме так описується послідовність. Сама заява проста; все це буде генерувати 2, 3, 4, ....

n=p[n-1];}

За допомогою хитрого повернення без повернення, з яким працює gcc, ми "повертаємо" останній елемент перших n термінів у послідовності, яка трапляється як n- й член.


3

Pyth, 29 байт

M?tH?eJ.DtHg1GghG-tHhJ+2hJ2g1

Спробуйте в Інтернеті

Як це працює

Замість того, щоб обдурити списки, тут використовується звичайна рекурсивна формула.

M                                def g(G, H):
 ?tH                                 if H - 1:
      J.DtHg1G                           J = divmod(H - 1, g(1, G))
    ?e                                   if J[-1]:
              ghG-tHhJ                       return g(G + 1, H - 1 - J[0])
                                         else:
                      +2hJ                   return 2 + J[0]
                                     else:
                          2              return 2
                           g1Q   print(g(1, eval(input())))

3

Haskell , 67 байт

0%j=2
i%j|d<-div i$f j=last$d+2:[(i-d-1)%(j+1)|d*f j<i]
f=(%1).pred

Спробуйте в Інтернеті!

Рекурсивне арифметичне рішення, яке виявилося в основному тим же методом, що і відповідь Піра Андерса Касеорга .

Цей код охоплений бородавками - потворними частинами, схожими на те, що їх можна було б відібрати в гольф, але я не бачив, як.

Функція i%jдійсно хоче використовувати захист, щоб перевірити, чи mod i(f j)>0оцінити один із відповідних двох виразів. Але обидва вирази використовують div i(f j). Якщо прив’язати це до варти, це не примусить його застосовуватись до обох сторін. Наскільки я знаю, охоронця не можна примушувати "розповсюджувати" на інших охоронців. letі whereзанадто довгі. Отже, код використовує lastдля вибору одного з двох виразів, тоді як захист прив'язує змінну. Тьфу.

В ідеалі ми б використовували, divModтому що і те, divі modвживається, але (d,m)<-divMod ...це вираження довге. Ми замість цього з нетерпінням перевіряємо мод ненульовим шляхом, бачимо, чи divзначення, яке ділить дільник, не відповідає початковому значенню.

0%j=2Випадку не буде необхідність , якщо Haskell короткого замикання div 0, що це не так. У .predПеретворює 1-індексований вхід нуля індексовані, або інакше було б -1поправки всюди.


Якщо ви повернете %1-індексовану, то вам потрібно виправлення п’яти байтів - що просто пов'язано.Однак ви можете вбудовувати fїх %безкоштовно і тоді fстає анонімним, щоб ви заощадили два байти.
Ørjan Johansen

@ ØrjanJohansen Що ти тут маєш на увазі під назвою? Я не бачу, як змінити посилання, fне втрачаючи байтів.
xnor

divModздається, на один байт дешевше, тому що це дозволяє розгалужувати !!(0^m). Поки що у мене є:1%j=2;i%j|(d,m)<-divMod(i-1)$j%1=[(i-d-1)%(j+1),d+2]!!(0^m);(%1)
Ørjan Johansen

Як бачите, вбудовування передбачає 1-реіндексінг, який видаляє .pred.
Ørjan Johansen

2

JavaScript (ES6), 98 93 91 байт

Рекурсивна функція, яка припиняється, як тільки результат з’являється.

f=(n,p,a=[...Array(n)])=>a[n-1]||f(n,-~p,a.map(c=>c?c:i?i++%(a[p]||2)?c:++v:(i=1,v=2),i=0))

Альтернативна версія, 90 байт

Запропоновано Shaggy за -1 байт

Цього треба викликати f(n)() . Хоча відповідна посада в мета наразі дає позитивну оцінку, цей синтаксис, мабуть, суперечить.

n=>g=(p,a=[...Array(n)])=>a[n-1]||g(-~p,a.map(c=>c?c:i?i++%(a[p]||2)?c:++v:(i=1,v=2),i=0))

Демо


n=>g=(p,a=[...Array(n)])=>a[n-1]||g(-~p,a.map(c=>c?c:i?i++%k?c:++v:(i=1,v=2),i=0,k=a[p]||2))повинна працювати на 92 байти. Телефонуйте за допомогою f(n)().
Кудлатий

@Shaggy Дякую! Додано як альтернативну версію.
Арнольд

1

Java 8, 124 байти

(i)->{int j=1,a[]=new int[i+1],k,s,n;for(;a[i]<2;){for(k=0,n=2;a[++k]>0;);for(s=a[j++]|2*k;k<=i;k+=s)a[k]=n++;}return a[i];}

Лямбда вираз.

Створює цілий масив і постійно заповнює його, поки n-е значення не заповнюється.

Попередньо оголосивши змінні вгорі, щоб скоротити якомога більше оголошень int коштує 4 байти простору на відміну від додавання,n який дорівнює 2.

На j"ітерації обчислення" кількість "пробілів", яку потрібно пропустити, дорівнює a[j](або 2, якщо порожнє). Виходить, що якщо перший порожній простір, який ми повинні заповнити, знаходиться в положенні k, він k * a[j]дає нам «крок» ( s).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.