Розчленовані номери


47

Я виявив цю послідовність під час роботи над Еволюцією OEIS , але ніколи не обійшовся , як розмістити її як відповідь. Написавши реалізацію довідника в Mathematica, я подумав, що це цікаве вправу, як окремий виклик, тому ось ми підемо.

Давайте побудуємо числовий реактор ділення! Розглянемо додатне ціле число N. Як приклад ми розглянемо 24. Щоб поділити це число, ми повинні знайти найбільшу кількість послідовних натуральних чисел, які дорівнюють N. У цьому випадку це 7 + 8 + 9 = 24. Тож ми розділилися 24на три нові числа. Але це не було б великим реактором поділу без ланцюгових реакцій. Тож давайте рекурсивно повторимо процес для цих компонентів:

       24
       /|\
      / | \
     /  |  \
    7   8   9
   / \     /|\
  3   4   / | \
 / \     /  |  \
1   2   2   3   4
           / \
          1   2

Зауважте, що ми зупиняємо процес, коли число не можна розкласти на менші послідовні цілі числа. Також зауважте, що ми могли писати 9як 4 + 5, але 2 + 3 + 4має більше компонентів. Тепер число Fission of Nвизначається як кількість цілих чисел, отриманих в цьому процесі, включаючи Nсебе. Наведене вище дерево має 13 вузлів, так F(24) = 13.

Ця послідовність є записом OEIS A256504 .

Перші 40 термінів, починаючи з N = 1, - це

1, 1, 3, 1, 5, 6, 5, 1, 6, 7, 12, 10, 12, 11, 12, 1, 8, 16, 14, 17, 18, 18,
23, 13, 21, 18, 22, 23, 24, 19, 14, 1, 22, 20, 23, 24, 31, 27, 25, 26

Перші 1000 термінів можна знайти в цій пастебі .

Змагання

Давши додатне ціле число N, визначте його число ділення F(N). (Тож вам не потрібно висвітлювати провідні 0списки на OEIS.)

Ви можете написати програму або функцію, взявши введення через STDIN (або найближчу альтернативу), аргумент командного рядка або аргумент функції та вивівши результат через STDOUT (або найближчу альтернативу), значення повернення функції або параметр функції (out).

Це кодовий гольф, тому найкоротша відповідь (у байтах) виграє.

Питання про бонус: чи можете ви знайти якісь цікаві властивості цієї послідовності?


Я зауважую, що OEIS, здається, має помилку при n = 34: починаючи з n = 32, він (наразі) перераховує 1, 22, 22, 23, 24, 31, а не 1, 22, 20, 23, 24, 31.
математика

1
@mathmandan Хороший улов, я, мабуть, пропоную виправлення (разом із першою схемою).
Мартін Ендер

Виклик, пов’язаний із цим: codegolf.stackexchange.com/questions/5703/… (і те саме питання про math.SE: math.stackexchange.com/questions/139842/… )
Ілмарі Каронен

@mathmandan FYI, я виправив послідовність та приклад зараз, а також додав свою контрольну реалізацію та перші 10k умови.
Мартін Ендер

Виглядає добре! Дякуємо за вашу роботу!
mathmandan

Відповіді:


16

Pyth, 23 22 21 байт

Lh&lJfqbsT.:tUb)syMeJ

Це визначає рекурсивну функцію y. Спробуйте в Інтернеті: Демонстрація

Пояснення:

L                      define a function y(b): return ...
            tUb          the list [1, 2, ..., b-1]
          .:   )         generate all consecutive sub-sequences
     f                   filter for sub-sequences T, which satisfy:
      qbsT                   b == sum(T)
    J                    and store them in J

                         return 
   lJ                        len(J)
  &                        and (if len(J) == 0 then 0 else ...)
                    eJ       last element of J (=longest sub-sequence) 
                  yM         recursive calls for all these numbers
                 s           sum
 h                         incremented by one (counting the current node)

52

Fission , 1328 989 887 797 байт

Ця відповідь трохи необґрунтовано довгий (я б хотів, щоб у нас були регістри, що складаються ) ... будь ласка, не забудьте прокрутити повз це і показати іншим відповідям якусь любов!

Робота над цим кодом була тим, що надихнула цей виклик. Я хотів додати відповідь у Fission до EOEIS, що привело мене до цієї послідовності. Однак насправді вивчення Fission та його реалізація потребували декількох тижнів, працюючи над ним і вимикаючи його. Тим часом послідовність дійсно зросла на мені, тому я вирішив поставити окремий виклик для цього (плюс, це не було б особливо далеко вниз по дереву на EOEIS).

Тож представляю тобі, Чудовисько:

 R'0@+\
/  Y@</ /[@ Y]_L
[? % \  / \ J
   \$@  [Z/;[{+++++++++L
UR+++++++++>/;
9\   ;    7A9
SQS  {+L  /$     \/\/\/\/\/   5/ @  [~ &@[S\/ \  D /8/
~4X /A@[  %5                   /; &    K  } [S//~KSA /
  3    \  A$@S  S\/  \/\/\/   \/>\ /S]@A  /  \ { +X
W7           X  X    /> \      +\ A\ /   \ /6~@/ \/
        /   ~A\;     +;\      /@
    ZX [K    / {/  / @  @ }  \ X @
       \AS   </      \V /    }SZS S/
         X   ;;@\   /;X  /> \ ; X X
 ;       \@+  >/ }$S SZS\+;    //\V
           / \\  /\; X X @  @  \~K{
           \0X /     /~/V\V /   0W//
    \        Z      [K \  //\
W       /MJ $$\\ /\7\A  /;7/\/ /
       4}K~@\ &]    @\  3/\
 /     \{   }$A/1 2  }Y~K <\
[{/\  ;@\@  /   \@<+@^   1;}++@S68
@\ <\    2        ;   \    /
$  ;}++ +++++++L
%@A{/
M  \@+>/
~     @
SNR'0YK
  \  A!/

Очікується, що на вході не буде зафіксованого нового рядка, тому ви, можливо, захочете його назвати так echo -n 120 | ./Fission oeis256504.fis.

Макет, можливо, все ще може бути більш ефективним, тому я думаю, що тут ще багато можливостей для вдосконалення (наприклад, він містить 911 581 461 374 пробілів).

Перш ніж ми перейдемо до пояснення, примітка про тестування цього: офіційний перекладач працює не так, як є. а) Mirror.cppне компілюється у багатьох системах. Якщо ви зіткнулися з цією проблемою, просто прокоментуйте рядовий рядок - зачіпаний компонент (випадкове дзеркало) не використовується в цьому коді. б) Є кілька помилок, які можуть призвести до невизначеної поведінки (і, ймовірно, буде для програми цей комплекс). Ви можете застосувати цей виправлення, щоб виправити їх. Щойно ви зробите це, ви зможете скласти перекладача

g++ -g --std=c++11 *.cpp -o Fission

Факт забави: ця програма використовує майже кожен компонент, який Fission може запропонувати, за винятком #(випадкове дзеркало), :(напівзеркальне відображення) -або |(звичайне дзеркало) та "(режим друку).

Що на Землі?

Попередження: Це буде досить довго ... Я припускаю, що ви щиро зацікавлені в тому, як працює Fission і як можна програмувати його. Тому що, якщо ви цього не зробите, я не впевнений, як я міг би це підсумувати. (Наступний параграф дає загальний опис мови.)

Fission - це двовимірна мова програмування, де і дані, і потік управління представлені атомами, що рухаються через сітку. Якщо ви бачили або використовували Marbelous раніше, концепція повинна бути нечітко знайомою. Кожен атом має дві цілі властивості: негативну масу та довільну енергію. Якщо маса коли-небудь стає негативною, атом видаляється з сітки. У більшості випадків ви можете трактувати масу як "величину" атома, а енергію - як якусь мета-властивість, яку використовують декілька компонентів для визначення потоку атомів (тобто більшість видів перемикачів залежать від знаку енергія). Я буду позначати атоми через (m,E), коли це необхідно. На початку програми сітка починається з купки(1,0)атоми, куди б ви не розмістили чотири компоненти UDLR(де буква позначає напрямок, яким атом рухається спочатку). Потім дошка заповнюється цілою купою компонентів, які змінюють масу та енергію атомів, змінюють їх напрямки або роблять інші більш складні речі. Повний список дивіться на сторінці esolangs , але я познайомлю більшість із них у цьому поясненні. Ще одним важливим моментом (який програма використовує кілька разів) є те, що сітка є тороїдальною: атом, який потрапляє на будь-яку зі сторін, знову з’являється в протилежну сторону, рухаючись в тому ж напрямку.

Я написав програму в декілька менших частин і зібрав їх наприкінці, тож я буду проходити пояснення.

atoi

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

Fission може читати лише значення байтів з окремих символів, а не цілих чисел. Хоча це є прийнятною практикою тут, я зрозумів, що перебуваючи на цьому, я міг би зробити це правильно і проаналізувати фактичні цілі числа на STDIN. Ось atoiкод:

     ;
 R'0@+\
/  Y@</ /[@ Y]_L
[? % \  / \ J 
   \$@  [Z/;[{+++++++++L
UR+++++++++>/;
           O

Два найважливіші компоненти Fission - це реактори поділу та плавлення. Розділюючі реактори є будь-яким із V^<>(вищевказаний код використовує <та >). Реактор ділення може зберігати атом (направляючи його в клин персонажа), за замовчуванням (2,0). Якщо атом потрапить на вершину персонажа, два нові атоми будуть відправлені в сторони. Їх маса визначається діленням вхідної маси на збережену масу (тобто вдвічі зменшується вдвічі) - лівий атом отримує це значення, а правий атом отримує решту маси (тобто маса зберігається при поділі) . Обидва вихідні атоми матимуть мінус вхідної енергіїнакопичена енергія. Це означає, що ми можемо використовувати реактори ділення для арифметики - як для віднімання, так і для ділення. Якщо в дію потрапить реактор поділу, атом просто відбивається по діагоналі і потім рухатиметься у напрямку до вершини персонажа.

Плавкі реактори є будь-яким із YA{}(вищевказаний код використовує Yта {). Їх функція схожа: вони можуть зберігати атом (за замовчуванням (1,0)), і при попаданні з вершини два нові атоми будуть відправлені в сторони. Однак у цьому випадку два атоми будуть однаковими, завжди зберігаючи надходить енергію та множуючи вхідну масу на збережену масу. Тобто, за замовчуванням термоядерний реактор просто дублює будь-який атом, що потрапив на його верхівку. При попаданні з боків термоядерні реактори дещо складніші: атом такожзберігається (незалежно від іншої пам'яті), поки атом не потрапить у протилежну сторону. Коли це станеться, новий атом вивільняється в напрямку до вершини, маса і енергія якої є сумою двох старих атомів. Якщо новий атом потрапить на ту саму сторону, перш ніж відповідний атом досягне протилежної сторони, старий атом просто буде перезаписаний. Плавкі реактори можна використовувати для здійснення додавання та множення.

Ще один простий компонент, який я хочу вийти з шляху, [і ]який просто задає напрямок атома вправо і вліво відповідно (незалежно від напрямку, що входить). Вертикальні еквіваленти M(вниз) і W(вгору), але вони не використовуються для atoiкоду. UDLRтакож діють як WM][після вивільнення своїх початкових атомів.

У будь-якому разі давайте подивимось на код там. Програма починається з 5 атомів:

  • RІ Lна дні просто отримати їх приріст маси (з +) , щоб стати , (10,0)а потім зберігали в розподілі і термоядерного реактора, відповідно. Ми будемо використовувати ці реактори для розбору входу базової 10.
  • У Lверхньому правому куті його маса зменшується (з _), щоб вона стала, (0,0)і зберігається в стороні термоядерного реактора Y. Це потрібно відслідковувати число, яке ми читаємо - ми поступово збільшуватимемо та множимо це, коли читатимемо числа.
  • У Rверхньому лівому куті його маса встановлюється символьним кодом 0(48) з '0, потім маса і енергія змінюються @і, нарешті, збільшуються один раз, +щоб дати (1,48). Потім його перенаправляють за допомогою діагональних дзеркал \і /зберігають у реакторі поділу. Ми будемо використовувати 48для віднімання, щоб перетворити вхід ASCII у фактичні значення цифр. Ми також повинні були збільшити масу, 1щоб уникнути поділу на 0.
  • Нарешті, Uлівий нижній кут - це те, що насправді приводить все в рух і спочатку використовується лише для управління потоком.

Після перенаправлення вправо, керуючий атом потрапляє ?. Це вхідний компонент. Він зчитує символ і встановлює масу атома на прочитане значення ASCII та енергію на 0. Якщо ми натиснемо EOF замість цього, енергія буде встановлена ​​на 1.

Атом продовжується і потім б’є %. Це дзеркальний вимикач. Для позитивної енергії це діє як /дзеркало. Але для позитивної енергії вона діє як \(а також зменшує енергію на 1). Тож поки ми читаємо символи, атом буде відображено вгору, і ми можемо обробити персонажа. Але коли ми закінчимо з введенням, атом буде відображено вниз, і ми зможемо застосувати різну логіку для отримання результату. FYI, протилежна складова &.

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

Перший характер атома потрапляє на термоядерний реактор (за замовчуванням) Y. Це розбиває атом, і ми використовуємо ліву копію як атом керування, щоб повернутися до вхідного компонента і прочитати наступний символ. Права копія буде оброблена. Розглянемо випадок, коли ми прочитали персонажа 3. Наш атом буде (51,0). Ми обмінюємось масою та енергією @, щоб ми могли використати віднімання наступного реактора ділення. Реактор віднімає 48енергію (не змінюючи масу), тому він відправляє дві копії (0,3)- енергія тепер відповідає цифрі, яку ми прочитали. Вихідна копія просто відкидається ;(компонент, який просто знищує всі вхідні атоми). Ми продовжуватимемо працювати зі спадною копією. Вам потрібно буде слідувати його шляху через/і \дзеркала трохи.

@Безпосередньо перед термоядерним реактором SWAPS маси і енергії знову, таким чином, що ми додамо (3,0)до нашого наростаючим підсумком в Y. Зверніть увагу, що сам по собі біг буде завжди мати 0енергію.

Зараз J- стрибок. Що вона робить, це стрибати будь-який вхідний атом вперед за своєю енергією. Якщо це так 0, атом просто продовжує рухатися прямо. Якщо це, 1то вона пропустить одну клітинку, якщо вона 2пропустить дві комірки тощо. Енергія витрачається в стрибку, тому атом завжди закінчується енергією 0. Оскільки загальний обсяг має нульову енергію, стрибок на даний момент ігнорується, і атом перенаправляється в реактор синтезу, {який помножує його масу на 10. Знижуюча копія відкидається, ;тоді як подаюча копія подається назад в Yреактор як новий загальний обсяг.

Вищезазначене постійно повторюється (у кумедний конвеєрний спосіб, коли обробляються нові цифри до того, як будуть зроблені попередні), поки ми не натиснемо EOF. Тепер %воля відправить атом вниз. Ідея полягає в тому, щоб перетворити цей атом (0,1)тепер, перш ніж потрапити на працюючий загальний реактор, щоб а) на загальну кількість не вплинуло (нульова маса) і б) ми отримаємо енергію, 1щоб перестрибнути через [. Ми можемо легко піклуватися про енергію $, яка збільшує енергію.

Проблема полягає в тому, ?що не скидається маса при натисканні на EOF, тому маса все одно буде останньою, прочитаної символом, і енергія буде 0(бо %зменшилася 1спина до 0). Тож ми хочемо позбутися цієї маси. Для цього ми знову обмінюємось масою та енергією @.

Мені потрібно ввести ще один компонент , перш ніж закінчити цей розділ: Z. Це по суті те саме, що %або &. Різниця полягає в тому, що вона дозволяє атомам позитивної енергії проходити прямо (при зменшенні енергії) і відхиляє атоми непозитивної енергії на 90 градусів зліва. Ми можемо використати це для усунення енергії атома, перебираючи його через Zі знову - як тільки енергія піде, атом відхилиться і залишить цикл. Ось така закономірність:

/ \
[Z/

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

Таким чином , коли атом покидає цю маленьку петлю, він буде (1,0)і місць , щоб (0,1)самі @до потрапляння в реакторі злитого випустити кінцевий результат введення. Однак загальний обсяг буде відключений в 10 разів, оскільки ми вже попередньо помножили його на іншу цифру.

Тож тепер з енергією 1цей атом буде пропускати [і стрибати в /. Це відводить його в реактор ділення, який ми підготували розділити на 10 і зафіксувати наше стороннє множення. Знову ж таки, ми відкидаємо одну половину, ;а іншу зберігаємо як вихід (тут представлено, Oщо просто надрукує відповідний символ і знищить атом - у повній програмі ми замість цього продовжуємо використовувати атом).

itoa

           /     \
input ->  [{/\  ;@
          @\ <\   
          $  ;}++ +++++++L
          %@A{/
          M  \@+>/
          ~     @
          SNR'0YK
            \  A!/

Звичайно, нам також потрібно перетворити результат назад у рядок і роздрукувати його. Ось для чого ця частина. Це передбачає, що вхід не надходить до позначки 10 або близько того, але в повній програмі, яка легко дається. Цей біт можна знайти в нижній частині повної програми.

Цей код представляє новий дуже потужний компонент Fission: стек K. Стек спочатку порожній. Коли атом з негативною енергією потрапляє в стек, атом просто висувається на стек. Коли атом з негативною енергією потрапить у стек, його масу та енергію замінять атом у верхній частині стека (який, таким чином, спливає). Якщо стек порожній, напрямок атома змінюється і його енергія стає позитивною (тобто множиться на -1).

Добре, повернімося до фактичного коду. Ідея itoaфрагмента полягає в тому, щоб багаторазово приймати модуль 10 введення, щоб знайти наступну цифру, при цьому ціле ділення введення на 10 для наступної ітерації. Це дасть усі цифри у зворотному порядку (від найменш значущих до найбільш значущих). Щоб виправити замовлення, ми натискаємо всі цифри на стек і наприкінці спливаємо їх по черзі, щоб надрукувати їх.

У верхній половині коду робиться обчислення цифр: Lз плюсами дає 10, яке ми клонуємо і подаємо в реактор поділу та синтезу, щоб ми могли розділити і помножити на 10. Петля по суті починається після [верхнього лівого кута . Поточне значення ділиться: одна копія ділиться на 10, потім множиться на 10 і зберігається в реакторі поділу, який потім потрапляє в іншу копію на вершині. Це обчислює i % 10як i - ((i/10) * 10). Зауважимо також, що Aрозбиває проміжний результат після ділення і перед множенням, таким чином, щоб ми могли перейти i / 10до наступної ітерації.

%Перерве цикл коли змінні ітерації хітів 0. Так як це більш-менш робити щось час циклу, цей код буде працювати навіть для друку 0(без створення провідних нулів в іншому випадку). Щойно ми залишаємо цикл, ми хочемо виповнити стек і надрукувати цифри. Sє протилежною Z, тому це перемикач, який буде відхиляти вхідний атом з позитивною енергією на 90 градусів праворуч. Таким чином, атом насправді рухається через край від Sпрямої до точки, Kщоб вискочити цифру (зверніть увагу на те, ~що забезпечує вхідний атом енергії -1). Ця цифра збільшується 48на отримання коду ASCII відповідного символу. AРозщеплює цифру надрукувати одну копію з!і подати іншу копію назад в Yреактор для наступної цифри. Друкована копія використовується як наступний тригер для стека (зауважте, що дзеркала також надсилають її по краю, щоб натиснути Mліворуч).

Коли стек порожній, Kволя відобразить атом і перетворить його енергію в +1такий, що він пройде прямо через S. Nдрукує новий рядок (тільки тому, що це акуратно :)). І тоді атом R'0знову повертається, щоб опинитися в стороні Y. Оскільки більше немає атомів навколо, це ніколи не буде випущено, і програма припиняється.

Обчислення номера ділення: Рамка

Давайте перейдемо до власне м’яса програми. Код, по суті, є портом моєї реалізації математичного довідника:

fission[n_] := If[
  (div = 
    SelectFirst[
      Reverse@Divisors[2 n], 
      (OddQ@# == IntegerQ[n/#] 
       && n/# > (# - 1)/2) &
    ]
  ) == 1,
  1,
  1 + Total[fission /@ (Range@div + n/div - (div + 1)/2)]
]

де divкількість цілих чисел у максимальному розділі.

Основні відмінності полягають у тому, що ми не можемо мати справу з значеннями напів цілого числа у Fission, тому я роблю багато речей, помножених на два, і що у Fission немає рекурсії. Щоб обійти це, я висуваю всі цілі числа в розділі в черзі, щоб пізніше їх обробити. Кожне число, яке ми обробляємо, збільшуватимемо лічильник на одне, і як тільки черга буде порожньою, ми випустимо лічильник та відправимо його на друк. (Черга, Qпрацює точно так само, як Kраз у порядку FIFO.)

Ось рамка для цієї концепції:

                      +--- input goes in here
                      v 

                     SQS ---> compute div from n          D /8/
                     ~4X               |                /~KSA /
                       3               +----------->    { +X
initial trigger ---> W                               6~@/ \/
                              4                   
                     W        ^                     /
                              |              3
                     ^     generate range    |
                     |     from n and div  <-+----- S6
                     |         -then-      
                     +---- release new trigger

Найважливіші нові компоненти - це цифри. Це телепортери. Всі телепортери з однаковою цифрою належать разом. Коли атом потрапить на будь-який телепортер, він буде негайно переміщений наступним телепортером у тій же групі, де наступний визначається у звичайному порядку вліво-вправо, зверху вниз. Це не обов'язково, але допоможіть у компонуванні (а значить, і в гольфі трохи). Є також, Xщо просто дублює атом, надсилаючи одну копію прямо вперед, а іншу назад.

На даний момент ви, можливо, зможете самі розібратися у більшості рамок. У верхньому лівому куті є черга значень, які ще обробляються, і випускає по черзі n. Один екземпляр nтелепортується донизу, тому що він нам потрібен при обчисленні діапазону, інший примірник переходить до блоку вгорі, який обчислює div(це далеко не найбільший розділ коду). Після того, divяк було обчислено, він дублюється - одна копія збільшує лічильник у верхньому правому куті, в якому зберігається K. Інший примірник телепортується донизу. Якщо це divбуло 1, ми негайно відхиляємо його вгору і використовуємо як тригер для наступної ітерації, не завдаючи жодних нових значень. Інакше ми використовуємо divіn у розділі внизу, щоб генерувати новий діапазон (тобто потік атомів із відповідними масами, які згодом ставлять у чергу), а потім відпустити новий тригер після завершення діапазону.

Після того, як черга буде порожньою, тригер буде відображений, проходячи прямо через Sі знову з'явившись у верхньому правому куті, де він вивільняє лічильник (кінцевий результат) з Aякого потім телепортується itoaчерез 8.

Обчислення номера ділення: Тіло петлі

Отже, все, що залишилося - це два розділи для обчислення divта генерації діапазону. Обчислення div- це ця частина:

 ;    
 {+L  /$     \/\/\/\/\/   5/ @  [~ &@[S\/ \
/A@[  %5                   /; &    K  } [S/
   \  A$@S  S\/  \/\/\/   \/>\ /S]@A  /  \ 
         X  X    /> \      +\ A\ /   \ /
    /   ~A\;     +;\      /@
ZX [K    / {/  / @  @ }  \ X @
   \AS   </      \V /    }SZS S/
     X   ;;@\   /;X  /> \ ; X X
     \@+  >/ }$S SZS\+;    //\V
       / \\  /\; X X @  @  \~K{
       \0X /     /~/V\V /   0W//
\        Z      [K \  //\
           \ /\7\A  /;7/\/

Ви, напевно, вже зараз бачили достатньо, щоб розібратися в цьому для себе з деяким терпінням. Розбивка на високому рівні така: Перші 12 стовпців або близько того генерують потік дільників 2n. Наступні 10 стовпців фільтрують ті, які не задовольняють OddQ@# == IntegerQ[n/#]. Наступні 8 стовпців фільтрують ті, які не задовольняють n/# > (# - 1)/2). Нарешті, ми висуваємо всі дійсні дільники на стек, і як тільки ми закінчимо, ми випорожнюємо весь стек в термоядерний реактор (перезаписуючи всі, крім останнього / найбільшого дільника), а потім випускаємо результат з подальшим усуненням його енергії (яка не була -зеро від перевірки нерівності).

Там є безліч шалених доріжок, які насправді нічого не роблять. Переважно \/\/\/\/божевілля вгорі ( 5s також є його частиною) та одна стежка навколо низу (що проходить через 7s). Мені довелося додати це, щоб боротися з деякими неприємними умовами гонки. Fission може використовувати компонент затримки ...

Код, що генерує новий діапазон, nі divце такий:

 /MJ $$\
4}K~@\ &]    @\  3/\
\{   }$A/1 2  }Y~K <\
 \@  /   \@<+@^   1;}++@
  2        ;   \    /

Спочатку обчислюємо n/div - (div + 1)/2(обидва терміни, які дають однаковий результат) і зберігаємо на потім. Тоді ми генеруємо діапазон від divвниз до 1і додаємо збережене значення до кожного з них.

В обох цих двох нових загальних моделей, які я повинен зазначити: Один є SXабо ZXпотрапляє знизу (або обертові версії). Це хороший спосіб дублювання атома, якщо ви хочете, щоб одна копія йшла прямо вперед (оскільки перенаправлення виходів термоядерного реактора іноді може бути громіздким). В Sабо Zобертається атом на , Xа потім повертає дзеркальну копію назад у вихідне напрям поширення.

Інша закономірність є

[K
\A --> output

Якщо ми зберігаємо в ньому будь-яке значення, Kми можемо неодноразово отримувати його, вражаючи Kнегативною енергією зверху. AДублює значення ми зацікавлені в тому, і посилає то , що копіювати правий на стек на наступний раз , коли нам це потрібно.

Що ж, це був цілком фальшивий ... але якщо ви насправді пережили це, я сподіваюся, ви зрозуміли, що Fission i͝s̢̘̗̗ ͢i̟nç̮̩r̸̭̬̱͔e̟̹̟̜͟d̙i̠͙͎̖͓̯b̘̠͎̭̰̼l̶̪̙̮̥̮y̠̠͎̺͜ ͚̬̮f̟͞u̱̦̰͍n͍ ̜̠̙t̸̳̩̝o ̫͉̙͠p̯̱̭͙̜͙͞ŕ̮͓̜o̢̙̣̭g̩̼̣̝r̩̼̣̝a̪̜͇m̳̭͔̤̞ͅ ͕̺͉̫̀ͅi͜n̳̯̗̳͇̹.̫̞̲̞̜̳


1
Now with 100% fewer scrollbars.так що ви кажете .. і його все ще буде продовжено ...
Оптимізатор

13
Ще читабельніші за більшість кодів, які викачують наші молодші розробники.
corsiKa

Як творець Fission, я ще не написав такої великої програми! Я вражений! Ваше пояснення є вражаючим і, безумовно, може послужити навчальним посібником для мови.
C0deH4cker

Крім того, останній рядок вашої відповіді виглядає як програма Fission;)
C0deH4cker

12

CJam, 42 41 байт

ri]{_{:X,:)_few:+W%{1bX=}=}%{,(},e_}h]e_,

Простий перший хід ширини і зупинка стану порожнього наступного рівня.

Як це працює :

ri]                                       e# This represents the root of the fissile tree
   {                               }h     e# Now we run a do-while loop
    _{                    }%              e# Copy the nodes at the current level and map them
                                          e# via this code block to get next level nodes
      :X,:)                               e# Store the node value in X and get array [1..X]
           _few                           e# Copy the array and get continuous slices of
                                          e# length 1 through X from the array [1..X]
               :+W%                       e# Right now, we have an array of array with each
                                          e# array containing slice of same length. We join
                                          e# those arrays and reverse them to get slices of
                                          e# higher length in front of lower lengths
                   {1bX=}=                e# Choose the first slice whose sum is same as X
                                          e# The reversal above makes sure that we give
                                          e# preference to slice of higher length in case of
                                          e# multiple slices add up to X
                            {,(},         e# Filter out slices of length 1 which basically
                                          e# mean that the current node cannot be split up
                                 e_       e# Join all slices in a single array. This is our
                                          e# next level in the Fissile tree. If this is empty
                                          e# it means that all no further node can be
                                          e# decomposed. In an {}h do-while loop, this fact
                                          e# itself becomes the stopping condition for the
                                          e# loop
                                     ]e_, e# Wrap all levels in an array. Flatten the array
                                          e# and take its length

Спробуйте його онлайн тут


Це, ймовірно, може бути гольф до близько 35 байт. Я намагаюся розібратися, як ..
Оптимізатор

10

Python 3, 112 байт

def f(n,c=0):
 d=n-c;s=(n-d*~-d/2)/d
 return(s%1or s<1)and f(n,c+1)or+(d<2)or-~sum(f(int(s)+i)for i in range(d))

4 байти збережено завдяки @FryAmTheEggman.

Пояснення надійде пізніше ...

Факт бонусу: Кожна потужність 2 має число поділу 1. Це тому, що сума послідовності парних довжин завжди є сумою двох середніх чисел, непарних, помножених на половину довжини послідовності, яка є цілою . Сума послідовності непарної довжини - це середнє число, помножене на довжину послідовності, яка непарна. Отже, оскільки сила 2 не має непарного дільника, вона може бути виражена лише як сума самої себе.


2 + 3 + 4 + 5 = 14, що не є дивним. Ваш аргумент для послідовностей парних довжин повинен бути змінений на "сума послідовності парних довжин - це сума двох середніх чисел, яка непарна, помножена на половину довжини". Решта вашої заяви проходить без змін.
Бруно Ле Флох

@BrunoLeFloch Дякую! Виправлено.
Випадкова

Чи не повинен ваш заголовок відображати покращення? тобто <strike> 117 </strike> <strike> 113 </strike> 112
corsiKa

@corsiKa Я зазвичай роблю це лише для великих вдосконалень. Інакше було б занадто багато вражених цифр.
randomra

8

Пітон 2, 111 102 97 байт

Дещо читабельний:

def f(n,c=0):a=n-c;b=n-a*~-a/2;return 1/a or-~sum(map(f,range(b/a,b/a+a)))if b>b%a<1else f(n,c+1)

Не начитаний:

def f(n,a=0):b=n-a*~-a/2;return b>0and(f(n,a+1)or b%a<1and(1/a or-~sum(map(f,range(b/a,b/a+a)))))

Обидва 97 байти.

b- nмінус (a-1)thтрикутне число. Якщо b % a == 0, то n- сума aпослідовних чисел, що починаються з b.


8
Я раніше вважав Python загальночитаною мовою, поки не приєднався до PPCG.
Олексій А.

Я думаю, вам потрібно вдосконалити своє визначення читабельності ..: P
Оптимізатор

Python 2 не дозволяє 1else. Працює лише 2-е рішення. Це не тільки Python 3, який elseможе відразу слідувати за номером.
mbomb007

@ mbomb007 Наскільки мені відомо, він працює чудово з 2.7.8 далі
Sp3000

Гаразд, я використовував 2.7.2.
mbomb007

7

Пітон 2, 86

f=lambda n,R={1}:n-sum(R)and f(n,R^{[min(R),max(R)+1][n>sum(R)]})or-~sum(map(f,R-{n}))

Менше гольфу:

def f(n,R={1}):
    d=sum(R)-n
    if d==0:return (sum(map(f,R-{n}))
    if d<0:return f(n,R|{max(R)+1})
    if d>0:return f(n,R-{min(R)})

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

Ми перевіряємо, як сума поточного пробігу порівнюється з потрібною сумою nчерез їх різницю.

  • Якщо сума занадто велика, ми вирізаємо найменший елемент за часом.
  • Якщо сума занадто мала, ми розширюємо пробіг, зробивши його макс більшим на 1.
  • Якщо сума правильна, ми повторюємо, відображаючи fпробіг, підсумовуючи і додаючи 1 для поточного вузла. Якщо запуск {n}, ми спробували всі можливі нетривіальні суми, зупиніть рекурсію, видаливши nспочатку.

Завдяки Sp3000 за економію 3 символів.


7

Пітон 2, 85

Я дуже пишаюся цією відповіддю, оскільки це вже займає десятки секунд за n = 9, а 5-10 хвилин - за n = 10. У коді гольф це вважається бажаним атрибутом програми.

f=lambda n,a=1,d=1:a/n or[f(a)+f(n-a,1+1%d*a)+1/d,f(n,a+d/n,d%n+1)][2*n!=-~d*(2*a+d)]

Існує також версія короткого замикання, яка не займає так багато часу і використовує однакову кількість байтів:

f=lambda n,a=1,d=1:a/n or~d*(2*a+d)+n*2and f(n,a+d/n,d%n+1)or f(a)+f(n-a,1+1%d*a)+1/d 

Це може бути швидше, але, принаймні, воно перевищує межу рекурсії за замовчуванням, як тільки n перейде трохи вище 40.

Ідея полягає в тому, щоб зробити грубі сили пошуку чисел aі dтак, щоб a + a+1 + ... + a+d == nза значеннями від 1 до n. f(n,a+d/n,d%n+1)Гілка рекурсії перебирає (a, d)пар. У випадку, якщо рівність задоволена, мені вдається уникнути дорогого map(range(...))виклику, розділившись лише на дві гілки незалежно від того, яка тривалість послідовності. Цифри a+1наскрізь dоб'єднуються в один виклик f, встановлюючи aпараметр так, що інший спосіб розділити послідовність неможливо.


Як це працює?
xnor

"Я дуже пишаюся цією відповіддю, тому що це вже займає десятки секунд за n = 9, а 5-10 хвилин для n = 10. У коді гольф це вважається бажаним атрибутом програми". Я поставив +1 саме для цього.
Soham Chowdhury

6

Haskell, 76 69 байт

f x=head$[1+sum(map f[y..z])|y<-[1..x-1],z<-[y..x],sum[y..z]==x]++[1]

Використання:

*Main> map f [1..40]
[1,1,3,1,5,6,5,1,6,7,12,10,12,11,12,1,8,16,14,17,18,18,23,13,21,18,22,23,24,19,14,1,22,20,23,24,31,27,25,26]

Як це працює:

[  [y..z] |y<-[1..x-1],z<-[y..x],sum[y..z]==x]

           make a list of lists with all consecutive integers (at least 2 elements)
           that sum up to x, sorted by lowest number, e.g. 9 -> [[2,3,4],[4,5]].

1+sum(map f[...]) 

           recursively calculate the Fission Number for each list

[...]++[1]

           always append the 1 to the list of Fission Numbers.

head

           take the first element, which is either the Fission Number of the
           longest list or if there's no list, the 1 appended in the step before.  

3

Сітківка , 66 байт

^|$
,
(`,(1+?)(?=(?<1>1\1)+\D)
$0;
+)`,(1*);1\1
,$1,1$1;
^,|1

.
1

Здійснює введення та друкує вихідні дані унітарно.

Ви можете розмістити кожен рядок у одному файлі або запустити код, як і -sпрапор. Наприклад:

> echo -n 1111111|retina -s fission
11111

Пояснення:

  • Ми зберігаємо список з числами, які потрібно розділити комою.
  • Для кожного числа ми беремо найменше початкове значення, яке може створити дійсне розбиття і відмежувати його від решти крапкою з комою.
  • Якщо всередині числа є крапка з комою, ми поміняємо його на коми і розміщуємо наступну належним чином розмір (довжина попереднього елемента + 1) частини числа.
  • Повторюємо кроки 2 і 3, поки не відбудуться зміни.
  • Ми отримуємо кому для кожного аркуша і крапку з комою для кожного внутрішнього вузла плюс додаткову кому, оскільки ми починали з двох комах. Отже, ми видаляємо кому та частини чисел ( 1-ів), а решту перетворюємо на 1's.

Стани рядка протягом усього процесу з введенням 11111111111111 (unary 14):

,11111111111111,
,11;111111111111,
,11,1;11,1111,11;111;,
,11,1,11;,1111,11,1;11;;,
,11,1,11;,1111,11,1,11;;;,
,,;,,,,;;;,
11111111111

Дуже дякую @MartinButtner за допомогу у чаті!


3

CJam (43 байти)

qi,{):X),_m*{{_)*2/}/-X=}=~\,>0\{~$+}/)}%W=

Демонстрація в Інтернеті

Я впевнений, що я пропускаю кілька хитрощів із розширеними циклами, але це акуратно використовує властивість CJam (що раніше мене дратувало), що всередині %карти результати залишаються у стеку, і тому можна отримати доступ за $допомогою а негативне зміщення.


Я познайомлюсь завтра, але для початку вам не потрібен ,на початку. /та %ще кілька інших людей неявно перетворюють числа в діапазони.
Мартін Ендер

,_m*можна замінити на 2m*. Формула арифметичної прогресії може бути замінена ~,>:Y_,+:+і ~\,>0\ перетворена !Y. Нарешті, якщо ви використовуєте {}#замість {}=, ви не потрібні )після того X. Збираємо все це разом:ri{):X2m*{~,>:Y_,+:+X=}#!Y{~$+}/)}%W=
Денніс

2

Ідіть, 133 байт

func 算(n int)int{Σ:=1;for i:=0;i<n;i++{for j:=0;j<n;j++{if i*i+i-j*j-j==2*n{for k:=j+1;k<=i;k++{Σ+=算(k)};j,i=n,n}}};return Σ}

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

При цьому використовується ідея, що роздільну "склад" також можна розглядати як різницю між двома послідовностями впорядкованих цілих чисел. Наприклад, візьміть роздільну "композицію" для числа 13. Це 6,7. Але це можна розглядати як суму цілих чисел 1 ... 7 мінус суму цілих чисел 1 ... 5

  A: 1 2 3 4 5 6 7  sum = 28
  B: 1 2 3 4 5      sum = 15 
A-B:           6 7  sum = 13, which is also 28-15 = 13

Згадаймо формулу зі шкільних днів Гаусса, сума 1 ... n = (n ^ 2 + n) / 2. Отже, щоб знайти композицію послідовних цілих чисел для даного n, ми також могли б сказати, що ми шукаємо 'кінцеві точки' p і q вздовж діапазону 1 ... n так, що (p ^ 2 + p) / 2 - ( q ^ 2 + q) / 2 = n. У наведеному вище прикладі ми шукали б "кінцеві точки" 5 і 7, тому що 7 ^ 2 + 7 = 56/2, 5 ^ 2 + 5 = 30/2, 56 / 2-30 / 2 = 28-15 = 13.

Зараз існує декілька можливих способів поділу числа, що розділяється, як зазначив Мартін 9 = 2 + 3 + 4, але також 4 + 5. Але здається очевидним, що "найнижча" стартова послідовність також буде найдовшою, бо потрібно більше малі цифри підсумовують велику кількість, ніж це середні великі числа. (На жаль, у мене немає доказів)

Отже, щоб знайти склад 9, протестуйте кожну 'кінцеву пару', p і q, ітерацію p і q окремо від 0 до 9, і перевірити, чи p ^ p + p / 2 - q ^ 2 + q / 2 = 9. Або, простіше кажучи, помножте рівняння на 2, щоб уникнути питань поділу округлення і зберегти всю математику на цілі числа. Тоді ми шукаємо p і q такі, що (p ^ p + p) - (q ^ q + q) = 9 * 2. Перший збіг, який ми знайдемо, буде кінцевими точками складу Fissile, оскільки, як зазначалося, найнижча група номерів також буде найдовшою, і ми шукаємо від низького до високого (0 до 9). Ми вириваємося з петлі, як тільки знаходимо відповідність.

Тепер рекурсивна функція знаходить ті "роздільні кінцеві точки" p і q для заданого n, а потім нагадує про себе для кожного з "дітей" у дереві від p до q. Для 9 він знайде 1 і 4, (20-2 = 18), тоді він повторно викликатиме себе на 2, 3 і 4, підсумовуючи результати. Для чисел, таких як 4, він просто ніколи не знаходить відповідності, і тому повертає "1". Це може бути короткотерміновим, але це як моя третя програма, і я не є експертом з рекурсії.

Дякуємо за прочитане


Хороша робота! Але чому імена функцій / змінних Unicode. Це коштує зайвих байтів, і ви, звичайно, могли просто використати звичайний лист?
Мартін Ендер

Дякуємо за добрий коментар. Але я запитав себе, чому б не рахувати символи замість байтів :)
нехай яскравий

Тому що це правила за замовчуванням. :) Причина, яку ми зазвичай рахуємо байтами, а не символами, полягає в тому, що в іншому випадку це відбувається , що мало цікаво для всіх учасників. ;) (Отож, будь-який автор виклику може вказати підрахунок символів замість байтів, але я конкретно цього не зробив.)
Мартін Ендер,

1

CJam, 40 35 33 байт

ri{__,f-_few:+{1b1$=}=|{F}*}:F~],

Дякуємо @Optimizer за пропозицію few, яка зберегла 2 байти.

Спробуйте його в Інтернеті в інтерпретаторі CJam .

Як це працює

ri      e# Read an integer from STDIN.
{       e# Define function F(X):
  _     e# Push X.
  _,    e# Push [0 ... X-1].
  f-    e# Subract each from X. Pushes Y := [X ... 1].
  _few  e# Push all overlapping slices of Y of length in Y.
  :+    e# Consolidate the slices of different lenghts in a single array.
  {     e# Find the first slice S such that...
    1b  e#   the sum of its elements...
    1$= e#   equals X.
  }=    e#   Since Y is in descending order, the first matching slice is also the longest.
  |     e# Set union with [X]. This adds X to the beginning of the S if S != [X].
  {F}*  e# Execute F for each element of S except the first (X).
}:F     e#
~       e# Execute F for the input.
],      e# Count the integers on the stack.

Якщо ви поєднаєте мою першу половину зі своєю другою половиною, ви отримаєте 34:ri{_,:)_few:+W%{1b1$=}=|{F}*}:F~],
Оптимізатор

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