Створіть мінімальну послідовність залишку


21

Кожне число можна представити, використовуючи нескінченно довгу послідовність залишку. Наприклад, якщо ми беремо число 7 і виконуємо 7mod2, то 7mod3, тоді 7mod4і так далі ми отримуємо 1,1,3,2,1,0,7,7,7,7,.....

Однак нам потрібна найкоротша можлива подальша частина, яка все ще може бути використана для того, щоб відрізнити її від усіх нижчих чисел. Повторне використання 7 [1,1,3]- це найкоротша послідовність, оскільки всі попередні підпорядкування не починаються з [1,1,3]:

0: 0,0,0,0...
1: 1,1,1,1...
2: 0,2,2,2...
3: 1,0,3,3...
4: 0,1,0,4...
5: 1,2,1,0...
6: 0,0,2,1...

Зверніть увагу, що [1,1] це не працює для представлення 7, оскільки його також можна використовувати для представлення 1. Однак слід вивести [1]з введенням 1.

Введення-виведення

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

Тестові приклади:

0: 0
1: 1
2: 0,2
3: 1,0
4: 0,1
5: 1,2
6: 0,0,2
7: 1,1,3
8: 0,2,0
9: 1,0,1
10: 0,1,2
11: 1,2,3
12: 0,0,0,2
30: 0,0,2,0
42: 0,0,2,2
59: 1,2,3,4
60: 0,0,0,0,0,4
257: 1,2,1,2,5,5
566: 0,2,2,1,2,6,6
1000: 0,1,0,0,4,6,0,1
9998: 0,2,2,3,2,2,6,8,8,10
9999: 1,0,3,4,3,3,7,0,9,0

Ось перші 10 000 послідовностей , якщо вам це цікаво (номери рядків відключені на 1).

Це , тому робіть його якомога коротше на улюбленій мові. Підроблені бонусні бали за будь-які швидкі відповіді!



@nimi ми говорили про це в чаті, і я вирішив, що послідовності повинні мати принаймні 1 елемент.
Натан Меррілл

1
Я трохи здивований, що ви не обмежили це простими залишками.
Ніл

Чи добре, якщо результат повертається у списку?
Р. Кап

@neil, я також вважав це, але оскільки залишки відрізняються складовими числами, я проголосував за його збереження
Nathan Merrill

Відповіді:


5

Математика, 60 53 байти

#~Mod~FirstCase[2~Range~#&/@Range[#+2],x_/;LCM@@x>#]&

Дещо швидко (він обробляє 10000 за ~ 0,1 секунди, але, швидше за все, не вистачить пам'яті на 100000).

Код видає помилку, але обчислює результат правильно.

Пояснення

Раніше в чаті ми виявили, що необхідні дільники завжди можна визначити як найкоротший список {1, 2, ..., n}, найменше загальне множинне яке перевищує вхідний. Короткий аргумент, чому це так: якщо LCM менше входу, то віднімання LCM від входу залишило б усі дільники незмінними, тому подання не є унікальним. Однак для всіх входів, менших за LCM, залишки будуть унікальними, інакше різниця між двома числами з рівними залишками буде меншою кратною всім дільниками.

Щодо коду ... як правило, порядок читання гольф Mathematica трохи смішно.

Range[#+2]

Це отримує нам список [1, 2, 3, ..., n+2]для введення даних n. Це +2полягає у тому, щоб переконатися, що вона працює правильно для 0та 1.

2~Range~#&/@...

Карта 2~Range~#(синтаксичний цукор для Range[2,#]) над цим списком, тому ми отримуємо

{{}, {2}, {2,3}, ..., {2,3,...,n+2}}

Це списки дільниць кандидатів (звичайно, це набагато більше, ніж нам потрібно). Тепер ми знайдемо перший з них, LCM перевищує вхідний з:

FirstCase[...,x_/;LCM@@x>#]

Більш синтаксис: x_це шаблон, який відповідає будь-якому зі списків і називає його x. До /;цього шаблону додається умова. Ця умова , LCM@@x>#де @@ застосовується функція до списку, тобто LCM@@{1,2,3}кошти LCM[1,2,3].

Нарешті, ми просто отримуємо всі залишки, використовуючи той факт, який Modє Listable, тобто він автоматично відображає список, якщо один з аргументів є списком (або якщо обидва вони є списками однакової довжини):

#~Mod~...

5

Желе , 14 байт

‘Ræl\>iṠ2»2r⁸%

При цьому використовується той факт, що рішення (якщо воно є) системи лінійних конгруенцій є унікальним за модулем LCM модулів. Спробуйте в Інтернеті! або перевірити всі тестові випадки .

Як це працює

‘Ræl\>iṠ2»2r⁸%  Main link. Argument: n

‘               Increment; yield n+1.
 R              Range; yield [1, ..., n+1].
  æl\           Cumulatively reduce by LCM.
                This yields [LCM(1), ..., LCM(1, ..., n+1)].
     >          Compare all LCMs with n.
      iṠ        Find the first index of sign(n).
                This yields the first m such that LCM(2, ..., m) > n if n > 0, and
                0 if n == 0.
        2»      Take the maximum of the previous result and 2, mapping 0 to 2.
          2r    Yield the range from 2 up to and including the maximum.
            ⁸%  Compute n modulo each integer in that range.

5

MATL , 24 байти

Дякуємо @nimi за вказівку на помилку в попередній версії цієї відповіді (тепер виправлена)

Q:qtQ!\t0Z)tb=YpsSP2):Q)

Це не вистачає пам'яті в онлайн-компіляторі для двох найбільших тестових випадків (але він працює на комп'ютері з 4 ГБ оперативної пам’яті).

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

Пояснення

Це застосовує визначення прямо. Для введення nвін обчислює масив , що містить 2D mod(p,q)з pвід 0до nі qвід 1до n+1. Кожен p- це стовпець, а кожен q- рядок. Наприклад, при введенні n=7цей масив є

0 0 0 0 0 0 0 0
0 1 0 1 0 1 0 1
0 1 2 0 1 2 0 1
0 1 2 3 0 1 2 3
0 1 2 3 4 0 1 2
0 1 2 3 4 5 0 1
0 1 2 3 4 5 6 0
0 1 2 3 4 5 6 7

Тепер останній стовпчик, який містить залишки n, є елементарним порівняно з кожним стовпцем цього масиву. Це дає

1 1 1 1 1 1 1 1
0 1 0 1 0 1 0 1
0 1 0 0 1 0 0 1
0 0 0 1 0 0 0 1
0 0 1 0 0 0 0 1
0 1 0 0 0 0 0 1
1 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1

де 1вказується рівність. Останній стовпець, очевидно, дорівнює собі і, таким чином, містить усі. Нам потрібно знайти стовпець , який має найбільшу кількість первинних , крім останнього стовпчика, і прийняти до відома , що число первинних одиниць, m. (У цьому випадку це другий стовпчик, який містить m=3початкові). З цією метою ми обчислюємо сукупний добуток кожного стовпця:

1 1 1 1 1 1 1 1
0 1 0 1 0 1 0 1
0 1 0 0 0 0 0 1
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1

то сума кожної колонки

1 3 1 2 1 2 1 8

а потім сортувати не все частіше і приймати друге значення, яке є 3. Це бажання m, яке вказує на те, скільки залишків нам потрібно вибрати.

Q:q    % take input n implicitly. Generare row array [0 1 ... n]
tQ!    % duplicate. Transform into column array [1; 2; ...; n-1]
\      % modulo, element-wise with broadcast. Gives the 2D array
t0Z)   % duplicate. Take last column
tb     % duplicate, bubble up
=      % test for equality, element-wise with broadcast
Yp     % cumumative product of each column
s      % sum of each column. This gives the number of initial coincidences
SP2)   % sort in decreasing order and take second value: m
:Q     % generate range [2 3 ... m+1]
)      % apply as index into array of remainders of n. Implicitly display

4

Желе , 13 11 байт

r¬µ%€R‘$ḟ/Ṫ

Це не виграє жодних очок швидкості брауні ... Спробуйте в Інтернеті! або перевірити менші тестові випадки .

Як це працює

r¬µ%€R‘$ḟ/Ṫ  Main link. Argument: n

r¬           Range from n to (not n).
             This yields [n, ..., 0] if n > 0 and [0, 1] otherwise.

  µ          Begin a new, monadic chain. Argument: A (range)

       $     Combine the previous two links into a monadic chain:
     R         Range; turn each k in A into [1, ..., k] or [] if k == 0.
      ‘        Increment to map k to [2, ..., k+1].
   %€        Take each k in A modulo all the integers in the 2D list to the right.
        ḟ/   Reduce by filter-not; sequentially remove all remainder sequences of
             n-1, ..., (not n) from the remainder sequences of n.
          Ṫ  Tail; take the last remainder sequence.
             This gives the shortest sequence for descending A and the longest one
             (i.e., [0]) for ascending A.

Чому ви включили дві відповіді ???
Ерік Аутгольфер

Тому що це два абсолютно різних підходи. Хоча цей показник на 3 байти коротший, інший насправді досить швидкий для обчислення всіх тестових випадків.
Денніс

Якби я був ти, я б цього не зробив ... за винятком випадків, коли це було голосуванням вгору / вниз.
Ерік Аутгольфер


3

Python 3,5, 117 95 78 байт

import sympy
r=lambda n,m=2,M=1,*l:M>n and l or r(n,m+1,sympy.lcm(m,M),*l,n%m)

Потрібен Python 3.5 та sympy ( python3 -m pip install --user sympy). Подяка @Dennis, щоб повідомити мені, що Python 3.5 дозволяє *lфокус із аргументами за замовчуванням.


З SymPy 0.7.5 ви можете скоротити M>n and lдо l*(M>n).
Денніс

3

Python 2, 73 70 69 65 байт

i=l=1
n=input()
while l<=n|1:
 i+=1;a=l;print n%i
 while l%i:l+=a

Повна програма. @Dennis врятував 4 байти, покращивши спосіб обробки нуля.


3

Haskell, 66 60 51 50 байт

f i=mod i<$>[2..2+sum[1|l<-scanl1 lcm[2..i],l<=i]]

Приклад використання: f 42-> [0,0,2,2]. Це алгоритм, описаний у відповіді @Martin Büttner .

Я збережу попередню версію для довідки, оскільки це досить швидко:

Haskell, 51 байт

f i=mod i<$>[[2..x]|x<-[2..],foldl1 lcm[2..x]>i]!!0

Це займає 0,03 секунди для f (10^100)мого п'ятирічного ноутбука.

Редагувати: @xnor знайшов байт для збереження. Спасибі!


Збереження байта шляхом підрахунку індексів, поки lcm не стане надто високим:h i=mod i<$>[2..2+sum[1|l<-scanl1 lcm[2..i],l<=i]]
xnor

2

Піта, 51 байт 66 байт

IqQZ[Z).q)IqQ1[1))IqQ2,0 1))FdhhQJu/*GHiGHtUd1I>JQVQ aY%QhN)<tYd.q

Спробуй!

Набагато більша швидкість 39-байтної версії (не працює для 0-2):

FdhhQJu/*GHiGHtUd1I>JQVtd aY%QhN)<tYd.q

Здається, це працює для абсурдно великих чисел, таких як 10 10 3

Примітка: ця відповідь не працює для 0, 1 і 2. Виправлено!


2

JavaScript (ES6), 81 77 байт

f=(n,r=[n%2],l=i=2,g=(j,k)=>j?g(k%j,j):k)=>l>n?r:f(n,[...r,n%++i],i/g(i,l)*l)

Це рекурсивно формує відповідь, поки LCM не перевищить початкове число. Зрозуміло, GCD також розраховується рекурсивно.

Редагувати: збережено 4 байти завдяки @ user81655.


@ user81655 Це просто непомітно ...
Ніл

2

Рубін, 52 байти

->n{m=t=1;a=[];(a<<n%m)until n<t=t.lcm(m+=1);a<<n%m}

Це рішення перевіряє всі можливі, mпочинаючи з 2, що є залишком, що робить послідовність унікальною. Те, що робить останній mунікальним, це не сама решта, а те m, що останній член найменшого діапазону, (2..m)де найменше спільне множина (LCM) цього діапазону більше, ніж n. Це пов'язано з китайською теоремою залишків, де для однозначного визначення того, яке число nє з кількістю залишків, LCM цих залишків повинен бути більшим, ніж n(якщо вибирати nз (1..n); якщо вибирати nз a..b, для вибору з LCM потрібно лише більше b-a)

Примітка. Я ставлю a<<n%mв кінці коду, оскільки until n<t=t.lcm(m+=1)коротке замикання раніше aотримало останній елемент, щоб зробити його унікальним.

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

Ungolfing:

def remainder_sequence(num)
  # starting with 1, as the statements in the until loop immediately increments divisor
  divisor = 1
  # starts with 1 instead of 2, as the statements in the until loop
  # immediately change product to a new lcm
  product = 1
  remainders = []

  # this increments divisor first then checks the lcm of product and divisor
  # before checking if num is less than this lcm
  until num < (product = product.lcm(divisor = divisor + 1))
    remainders << num % divisor
  end

  # until always short circuits before the last element is entered
  # so this enters the last element and returns
  return remainders << num % divisor
end


1

Python 3.5, 194 181 169 152 149 146 байт:

( Спасибі @ Sherlock9 за 2 байти! )

def r(o,c=0):
 y=[[j%i for i in range(2,100)]for j in range(o+1)]
 while 1:
  c+=1;z=y[-1][:c]
  if z not in[f[:c]for f in y[:-1]]:break
 print(z)

Працює чудово, а також досить швидко. Розрахунок мінімальної залишкової послідовності 100000виходів [0, 1, 0, 0, 4, 5, 0, 1, 0, 10, 4, 4]і зайняв лише близько 3 секунд. Він навіть зміг обчислити послідовність для введення1000000 (1 мільйон), виходу [0, 1, 0, 0, 4, 1, 0, 1, 0, 1, 4, 1, 8, 10, 0, 9]і зайняв близько 60 секунд.

Пояснення

В основному, ця функція - це спершу створити список, yз усім, j mod iде jє кожне ціле число в діапазоні 0=>7(включаючи 7) і iкожне ціле число в діапазоні 0=>100. Потім програма переходить у нескінченний whileцикл і порівнює однакову кількість вмісту кожного підспису в межах перших по другому підписних списків y( y[:-1:]) з однаковою кількістю елементів в останньому y[-1]списку ( ) списку y. Коли підсписокy[-1] є іншим ніж будь-який інший підпис, цикл розбивається, і повертається правильна мінімальна послідовність залишку.

Наприклад, якщо вхід 3, yбуде:

[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [1, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]]

Потім, коли він входить у цикл while, він порівнює кожен підпис у списку y[:-1:]з однаковою кількістю елементів у списку y[-1]. Наприклад, спочатку було б порівняти [[0],[1],[0]]і [1]. Оскільки останній підпис є в решті y, він буде продовжуватися, а потім порівнювати [[0,0],[0,1],[0,2]]і [1,0]. Оскільки [1,0]зараз НЕ в іншому порядку y в такому конкретному порядку , це мінімальна послідовність нагадування, і, отже, [1,0]буде правильно повернуто.


Щоб зберегти байти, y[:c:]те саме, щоy[:c]
Sherlock9,

0

C89, 105 байт

g(a,b){return b?g(b,a%b):a;}main(n,m,M){scanf("%d",&n);for(m=M=1;(M=++m*M/g(m,M))<=n;)printf("%d ",n%m);}

Компілюється (із застереженнями), використовуючи gcc -std=c89. Бере єдине число на stdin і виводить послідовність залишків, розділених пробілами в stdout.


1
Це не надрукує нічого, коли n = 0
xsot

0

C, 89 байт

a,i=2;main(l,n){for(n=atoi(gets(n))?:!puts(n);n/l;printf("%d ",n%i++))for(a=l;l%i;l+=a);}

Компілюйте з gcc. Спробуйте в Інтернеті: n = 59 , n = 0 .

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