Generieren Sie die minimale Restsequenz

21

Jede Zahl kann mit einer unendlich langen Restsequenz dargestellt werden. Zum Beispiel, wenn wir die Zahl 7, nehmen und ausführen 7mod2, dann 7mod3, dann 7mod4, und so weiter, wir bekommen 1,1,3,2,1,0,7,7,7,7,.....

Wir brauchen jedoch die kürzestmögliche verbleibende Teilsequenz, die noch verwendet werden kann, um sie von allen niedrigeren Zahlen zu unterscheiden. Das erneute Verwenden von 7 [1,1,3]ist die kürzeste Untersequenz, da nicht alle vorherigen Untersequenzen mit Folgendem beginnen [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...

Beachten Sie, dass [1,1] die Darstellung von 7 nicht funktioniert, da sie auch zur Darstellung [1]von 1 verwendet werden kann. Sie sollten jedoch mit einer Eingabe von 1 ausgeben .

Input-Output

Ihre Eingabe ist eine nicht negative Ganzzahl. Sie müssen eine Sequenz oder Liste der Restsequenz mit minimaler Länge wie oben definiert ausgeben.

Testfälle:

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

Hier sind die ersten 10.000 Sequenzen , falls Sie interessiert sind (die Zeilennummern sind um 1 versetzt).

Dies ist ein , also mach es so kurz wie möglich in deiner Lieblingssprache. Gefälschte Bonuspunkte für schnelle Antworten!

Nathan Merrill
quelle
Related
Peter Taylor
@nimi wir haben darüber im Chat gesprochen und ich habe entschieden, dass Sequenzen mindestens 1 Element lang sein müssen.
Nathan Merrill
1
Ich bin etwas überrascht, dass Sie es nicht auf die wichtigsten Reste beschränkt haben.
Neil
Ist es in Ordnung, wenn die Ausgabe in einer Liste zurückgegeben wird?
R. Kap
@neil, ich habe auch darüber nachgedacht, aber da die Reste bei zusammengesetzten Zahlen unterschiedlich sind, habe ich dafür gestimmt, sie beizubehalten
Nathan Merrill

Antworten:

5

Mathematica, 60 53 Bytes

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

Etwas schnell (es verarbeitet 10000 in ~ 0,1 Sekunden, aber wahrscheinlich wird der Speicher für 100000 ausgehen).

Der Code löst einen Fehler aus, berechnet das Ergebnis jedoch korrekt.

Erläuterung

Wir haben zuvor im Chat festgestellt, dass die erforderlichen Teiler immer als die kürzeste Liste bestimmt werden können, {1, 2, ..., n}deren kleinstes gemeinsames Vielfaches die Eingabe überschreitet. Ein kurzes Argument, warum das so ist: Wenn die LCM kleiner als die Eingabe ist, bleiben beim Subtrahieren der LCM von der Eingabe alle Divisoren unverändert, sodass die Darstellung nicht eindeutig ist. Für alle Eingaben, die kleiner als der LCM sind, sind die Reste jedoch eindeutig, da der Unterschied zwischen zwei Zahlen mit gleichen Resten ein kleineres Vielfaches aller Teiler wäre.

Was den Code angeht ... wie immer ist die Lesereihenfolge von Mathematica ein bisschen lustig.

Range[#+2]

Dies bringt uns eine Liste [1, 2, 3, ..., n+2]zur Eingabe n. Damit +2soll sichergestellt werden, dass es für 0und richtig funktioniert 1.

2~Range~#&/@...

Map 2~Range~#(syntaktischer Zucker für Range[2,#]) über diese Liste, so bekommen wir

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

Dies sind Kandidaten-Divisor-Listen (natürlich ist das im Allgemeinen viel mehr, als wir brauchen werden). Jetzt finden wir den ersten von ihnen, dessen LCM die Eingabe mit überschreitet:

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

Weitere Syntax: x_ist ein Muster, das mit einer der Listen übereinstimmt und diese aufruft x. Das /;hängt eine Bedingung an dieses Muster an. Diese Bedingung ist , LCM@@x>#wo @@ gilt die Funktion in die Liste, dh LCM@@{1,2,3}Mittel LCM[1,2,3].

Schließlich haben wir einfach alle die Reste erhalten, die Tatsache zunutze machen , die Modist Listable, dh es automatisch eine Liste Karten über , wenn eines der Argumente eine Liste (oder wenn beide Listen der gleichen Länge sind):

#~Mod~...
Martin Ender
quelle
5

Jelly , 14 Bytes

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

Dies nutzt die Tatsache, dass die Lösung (falls vorhanden) eines Systems linearer Kongruenzen einzigartig ist, modulo das LCM der Module. Probieren Sie es online! oder überprüfen Sie alle Testfälle .

Wie es funktioniert

‘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.
Dennis
quelle
5

MATL , 24 Bytes

Vielen Dank an @nimi für den Hinweis auf einen Fehler in einer früheren Version dieser Antwort (jetzt korrigiert)

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

Dies hat nicht genügend Speicher im Online-Compiler für die beiden größten Testfälle (funktioniert jedoch auf einem Computer mit 4 GB RAM).

Probieren Sie es online!

Erläuterung

Dies wendet die Definition auf einfache Weise an. Für die Eingabe nberechnet sie einen 2D - Array enthält , mod(p,q)mit pvon 0zu nund qvon 1zu n+1. Jedes pist eine Spalte und jedes qist eine Zeile. Bei der Eingabe ist n=7dieses Array beispielsweise

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

Nun ist die letzte Spalte, die die Reste von enthält, im nVergleich zu jeder Spalte dieses Arrays elementweise. Dies ergibt

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

wo 1gibt Gleichheit. Die letzte Spalte ist offensichtlich gleich sich selbst und enthält somit alle. Wir müssen die Spalte finden, die die größte Anzahl von Anfangsspalten außer der letzten hat, und diese Anzahl von Anfangsspalten notieren m. (In diesem Fall ist es die zweite Spalte, die m=3anfängliche enthält ). Zu diesem Zweck berechnen wir das kumulative Produkt jeder Spalte:

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

dann die Summe jeder Spalte

1 3 1 2 1 2 1 8

und dann nicht zunehmend sortieren und den zweiten Wert nehmen, der ist 3. Dies ist der gewünschte Wert m, der angibt, wie viele Reste ausgewählt werden müssen.

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
Luis Mendo
quelle
4

Jelly , 13 11 Bytes

r¬µ%€R‘$ḟ/Ṫ

Dies wird keine Geschwindigkeit Brownie Punkte gewinnen ... Probieren Sie es online! oder überprüfen Sie die kleineren Testfälle .

Wie es funktioniert

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.
Dennis
quelle
Warum hast du zwei Antworten hinzugefügt ???
Erik der Outgolfer
Weil es zwei völlig unterschiedliche Ansätze sind. Während diese Option 3 Byte kürzer ist, ist die andere tatsächlich schnell genug, um alle Testfälle zu berechnen.
Dennis
Wenn ich Sie wäre, hätte ich es nicht getan ... es sei denn, es wäre eine Sache mit Auf- und Abstimmen.
Erik der Outgolfer
3

Python 3.5, 117 95 78 Bytes

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)

Benötigt Python 3.5 und sympy ( python3 -m pip install --user sympy). Dank an @Dennis, um mich zu benachrichtigen, dass Python 3.5 den *lTrick mit Standardargumenten zulässt .

orlp
quelle
Mit SymPy 0.7.5 können Sie verkürzen M>n and lzu l*(M>n).
Dennis
3

Python 2, 73 70 69 65 Bytes

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

Ein volles Programm. @Dennis sparte 4 Bytes, indem die Art und Weise, wie mit Null umgegangen wird, verbessert wurde.

xsot
quelle
3

Haskell, 66 60 51 50 Bytes

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

Anwendungsbeispiel: f 42-> [0,0,2,2]. Es ist der in @Martin Büttners Antwort beschriebene Algorithmus .

Ich werde die vorherige Version als Referenz behalten, weil es ziemlich schnell ist:

Haskell, 51 Bytes

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

Bei f (10^100)meinem fünf Jahre alten Laptop dauert es 0,03s .

Edit: @xnor hat ein zu speicherndes Byte gefunden. Vielen Dank!

nimi
quelle
Speichern eines Bytes durch Zählen der Indizes, bis der lcm zu hoch wird:h i=mod i<$>[2..2+sum[1|l<-scanl1 lcm[2..i],l<=i]]
xnor
2

Pyth, 51 Bytes 66 Bytes

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

Versuch es!

Viel höhere Geschwindigkeit 39-Byte-Version (funktioniert nicht für 0-2):

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

Es scheint für absurd große Zahlen wie 10 10 3 zu funktionieren

Hinweis: Diese Antwort funktioniert nicht für 0, 1 und 2. Behoben!

poi830
quelle
2

JavaScript (ES6), 81,77 Byte

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)

Dies baut die Antwort rekursiv auf, bis die LCM die ursprüngliche Zahl überschreitet. Die GCD wird natürlich auch rekursiv berechnet.

Bearbeiten: 4 Bytes dank @ user81655 gespeichert.

Neil
quelle
@ user81655 Das ist nur hinterhältig ...
Neil
2

Ruby, 52 Bytes

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

Diese Lösung prüft alles Mögliche m ab 2, die den Rest ausmachen, der die Sequenz einzigartig macht. Was das letzte meinzigartig macht, ist nicht der Rest selbst, sondern mdas letzte Mitglied des kleinsten Bereichs, (2..m)in dem das kleinste gemeinsame Vielfache (LCM) dieses Bereichs größer ist als n. Dies ist auf das chinesische Resttheorem zurückzuführen. Um die nAnzahl der Reste eindeutig zu bestimmen , muss der LCM dieser Reste größer sein als n(bei Auswahl nvon (1..n); bei Auswahl nvon a..bmuss der LCM nur größer sein als b-a).

Hinweis: Ich habe a<<n%mam Ende des Codes wegen until n<t=t.lcm(m+=1)Kurzschlüssen vora das letzte Element erhalten haben, um ihn eindeutig zu machen.

Wenn jemand Golfvorschläge hat, lass es mich bitte in den Kommentaren oder im PPCG-Chat wissen .

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
Sherlock9
quelle
1

Python 3.5, 194 181 169 152 149 146 Bytes:

( Danke an @ Sherlock9 für 2 Bytes! )

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)

Funktioniert perfekt und ist auch ziemlich schnell. Berechnung für die minimale Restsequenz von100000 Ausgaben [0, 1, 0, 0, 4, 5, 0, 1, 0, 10, 4, 4]dauerte nur ca. 3 Sekunden. Es war sogar in der Lage, die Reihenfolge für die Eingabe 1000000(1 Million), Ausgabe zu berechnen[0, 1, 0, 0, 4, 1, 0, 1, 0, 1, 4, 1, 8, 10, 0, 9] , und es dauerte ungefähr 60 Sekunden.

Erläuterung

Grundsätzlich erstellt diese Funktion zunächst eine Liste ymit allen Stellen , an j mod idenen jsich jede ganze Zahl im Bereich 0=>7(einschließlich 7) und ijede ganze Zahl im Bereich befindet 0=>100. Das Programm geht dann in eine whileEndlosschleife und vergleicht die gleiche Anzahl von Inhalten jeder Unterliste in der ersten bis zur vorletzten Unterliste von y( y[:-1:]) mit der gleichen Anzahl von Elementen in der letzten Unterliste ( y[-1]) von listy . Wenn sublist y[-1]ist anders als jeder anderer Subliste, wird die Schleife aus gebrochen, und die korrekten minimalen Rest - Sequenz zurückgeführt wird.

Wenn zum Beispiel die Eingabe 3 ist, y wäre dies:

[[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]]

Wenn es dann in die while-Schleife eintritt, vergleicht es jede Unterliste in der Liste y[:-1:]mit der gleichen Anzahl von Elementen in der Unterliste y[-1]. Zum Beispiel würde es zuerst vergleichen [[0],[1],[0]]und [1]. Da sich die letzte Unterliste im Rest von befindet y, würde es weitergehen und dann vergleichen [[0,0],[0,1],[0,2]]und [1,0]. Da [1,0]jetzt NICHT mehr in y dieser bestimmten Reihenfolge vorkommt , ist dies die minimale Erinnerungssequenz und [1,0]würde daher korrekt zurückgegeben.

R. Kap
quelle
Das Speichern von Bytes y[:c:]ist dasselbe wiey[:c]
Sherlock9
0

C89, 105 Bytes

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);}

Kompiliert (mit Warnungen) mit gcc -std=c89. Nimmt eine einzelne Zahl auf stdin und gibt die durch Leerzeichen auf stdout getrennte Folge von Resten aus.

orlp
quelle
1
Dies gibt nichts aus, wenn n = 0
xsot
0

C 89 Bytes

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);}

Kompiliere mit gcc. Probieren Sie es online aus: n = 59 , n = 0 .

xsot
quelle