La tua base in 1-2-3-Tribonacci in binario torna alla tua base


19

sfondo

La sequenza 1-2-3-Tribonacci

Immagina per un secondo che potresti creare una sequenza di fibonacci sostituendo la formula di iterazione standard con la seguente:

tribonacci

In sostanza, invece di sommare gli ultimi due per ottenere il successivo, si sommano gli ultimi tre. Questa è la base per la sequenza 1-2-3-Tribonacci.

Criterio di Brown

Il criterio di Brown afferma che è possibile rappresentare qualsiasi valore intero come somma dei membri di una sequenza a condizione che:

  1. x sub n è uguale a 1

  2. Per tutti nmaggiori di 1,x sub n minore di 2 x sub n - 1

Cosa significa questo per la sfida

Puoi descrivere qualsiasi numero intero positivo come una somma di membri della sequenza 1-2-3-Tribonacci formata dalle seguenti condizioni iniziali:

condizioni iniziali

Questo è noto come, per ogni valore in questa sequenza, il rapporto tra i termini non è mai maggiore di 2 (il rapporto è in media a circa 1.839).

Come scrivere in questo sistema di rappresentazione numerica

Diciamo che usi una rappresentazione little-endian. Allinea i membri della sequenza in questo modo:

1  2  3  6 11 20 37 68

Quindi prendi il tuo numero per essere rappresentato (per i nostri test, diciamo che è 63) e trovi i valori del dato 1-2-3-Tribonacci che sommano a 63 (usando prima i valori più grandi!) . Se il numero fa parte della somma, inserisci un 1 sotto di esso, 0 in caso contrario.

1  2  3  6 11 20 37 68
0  0  0  1  0  1  1  0

Puoi farlo per ogni dato intero - verifica solo di utilizzare prima i valori più grandi sotto il tuo dato input!

Definizione (finalmente)

Scrivi un programma o una funzione che eseguirà le seguenti operazioni con un input intero positivo n(scritto in qualsiasi base standard) tra 1 e il valore massimo della tua lingua:

  1. Converti il ​​valore nella rappresentazione numerica definita 1-2-3-Tribonacci.
  2. Usando questa rappresentazione di tipo binario, e leggila come se fosse binaria. Ciò significa che le cifre rimangono invariate, ma ciò che significano cambia.
  3. Prendi questo numero binario e convertilo nella base del numero originale.
  4. Emette o restituisce questo nuovo numero.

Tuttavia, finché l'output è valido, non è necessario seguire questi passaggi. Se trovi magicamente una formula più corta (e matematicamente equivalente), sentiti libero di usarla.

Esempi

Lascia che la funzione fsia la funzione descritta dalla definizione e che []rappresenti i passaggi eseguiti (come little-endian, anche se non dovrebbe importare) (non è necessario seguire questo processo, questo è solo il processo descritto):

>>> f(1)
[1]
[1]
[1]
1

>>> f(5)
[5]
[0, 1, 1]
[6]
6

>>> f(63)
[63]
[0, 0, 0, 1, 0, 1, 1]
[104]
104

Posso presentare un programma separato che, se non altrettanto breve, risolverà la domanda più rapidamente? log (log (n)) + n time rispetto a log (n) + n time. Vai vai ennesima matrice di potenza.
fəˈnɛtɪk,

@LliwTelracs Non posso impedirti di pubblicare le tue soluzioni. Rendi il target del metodo di soluzione il più conciso possibile per assicurarti di competere nel campo giusto.
Addison Crump,

Beh, non lo farò almeno. La rapida esponenziazione di questa matrice è ridicolmente dettagliata
f 7nɛtɪk

2
@LliwTelracs Forse potresti semplicemente aggiungerlo come addendum al tuo post esistente allora.
Jonathan Allan,

la tua sfida è illeggibile per coloro che non possono mostrare immagini.
Mindwin

Risposte:


7

Javascript 117 111 byte

Grazie a @theonlygusti per l'aiuto nel golf con 5 byte

x=>{r=0;a=[1,2,3];i=1;while(a[++i]<x)a[i+1]=a[i]+a[i-1]+a[i-2];for(;x;i--)if(x>=a[i]){r+=1<<i;x-=a[i]}return r}

Come funziona

Innanzitutto, la funzione genera tutti i numeri tribonacci fino a quando non trova uno maggiore dell'input

a=[1,2,3];i=1;for(;a[++i]<x;)a[i+1]=a[i]+a[i-1]+a[i-2];

Successivamente, ricerca inversa l'elenco dei numeri. Se un numero è inferiore all'input, aggiunge 2 ^ (indice di quel numero) al valore restituito e riduce l'input di quel numero.

for(;x;i--)if(x>=a[i]){r+=1<<i;x-=a[i]}

Alla fine restituisce il risultato.

Provalo online


1
che dire a[++i]<xall'interno della condizione for per salvare un byte?
theonlygusti,

1
Inoltre, è possibile sostituire x>0con x. Salva altri 2 byte.
theonlygusti,

È un algoritmo piuttosto buono. oo
Addison Crump,

7

Python 2 , 110 102 byte

-3 byte grazie a Rod (trucco accurato per lanciare un valore booleano iin un int con +iil `+i`funzionamento della repr )

n=input()
x=[3,2,1]
r=''
while x[0]<n:x=[sum(x[:3])]+x
for v in x:i=n>=v;n-=v*i;r+=`+i`
print int(r,2)

Provalo online!


1
puoi sostituirlo '01'[i]con`+i`
Rod

iè un booleano non un int. Modifica - Ohhh +i, pulito.
Jonathan Allan,

3
@Rod È un trucco nei consigli e nei trucchi di Python 2?
Addison Crump,

@VotoToChiudi Non credo proprio
Rod

7

JavaScript (ES6), 97 93 byte

Qui, stiamo usando reduce()una funzione ricorsiva. Partiamo dal presupposto che l'output è a 31 bit (che è la più grande quantità senza segno con cui JS può facilmente lavorare per operazioni bit a bit).

n=>[...Array(x=31)].reduce(p=>(c=(F=k=>k<4?k:F(--k)+F(--k)+F(--k))(x--))>n?p:(n-=c,p|1<<x),0)

Per quanto riguarda le prestazioni, questo chiaramente non è molto efficiente.

Per i curiosi:

  • Il rapporto tra il numero di chiamate F()per N + 1 reduce()iterazioni e N iterazioni converge rapidamente verso la costante Tribonacci (≈ 1.83929). Pertanto, ogni bit aggiuntivo nell'output costa circa il doppio del tempo precedente.
  • Con 31 bit, la F()funzione viene chiamata ben 124 milioni di volte.

Test

NB: il completamento potrebbe richiedere 1 o 2 secondi.


Wow, questo è in ritardo sul mio browser quando lo uso. xD
Addison Crump

@VotoToClose Prestazioni sagge, questo è terribilmente inefficiente. :-) Il codice di test non dovrebbe rimanere troppo a lungo, però. Nella mia scatola ottengo circa 600 ms in Firefox e 900 ms in Chrome. È molto più lento dalla tua parte?
Arnauld,

5 secondi. xD
Addison Crump

@VoteToClose Ora dovrebbe essere un po 'più veloce. La 32a iterazione era inutile, quindi ho limitato l'output a un numero intero a 31 bit senza segno.
Arnauld

6

Mathematica, 78 74 byte

Fold[#+##&,#~NumberDecompose~Reverse@LinearRecurrence[{1,1,1},{1,2,3},#]]&

LinearRecurrence[{1,1,1},{1,2,3},#]genera un elenco, di lunghezza uguale all'input, dei numeri tribonacci 1-2-3. (Il {1,1,1}rappresenta la somma dei tre termini precedenti, mentre {1,2,3}sono i valori iniziali.) Quindi #~NumberDecompose~trova il modo più avaro di scrivere l'input come somma degli elementi dell'elenco (questa è la stessa funzione che decompone un importo monetario in multipli di le valute disponibili, ad esempio). Infine, Fold[#+##&,...]converte l'elenco binario risultante in un numero intero (base-10).

Presentazione precedente:

Fold[#+##&,#~NumberDecompose~Reverse@Array[If[#<4,#,Tr[#0/@(#-Range@3)]]&,#]]&

Come spesso accade (anche se non sopra), questa versione golfata è super lenta su input maggiori di circa 20, perché genera (con ricorsione non ottimizzata) un elenco di tribù la cui lunghezza è l'input; la sostituzione della finale #con un limite più ragionevole come il Round[2Log@#+1]risultato si traduce in prestazioni molto migliori.


Whaat? Mathematica non ha un 123Tribonacci[]builtin?
palsch,

1
Non esattamente, anche se si scopre che l'uso di un builtin aiuta un po '.
Greg Martin

5

Haskell, 95 byte

(a!b)c=a:(b!c)(a+b+c)
e#(r,c)|c-e<0=(2*r,c)|1<2=(2*r+1,c-e)
f n=fst$foldr(#)(0,n)$take n$(1!2)3

Esempio di utilizzo: f 63-> 104. Provalo online! .

Come funziona: !costruisce la sequenza 1-2-3-Tribonacci. Dato 1, 2e 3come parametri di partenza, prendiamo i primi nelementi della sequenza. Poi pieghiamo dalla funzione destra #, che sottrae l'elemento successivo eda ne imposta il bit del valore di ritorno r, se eè necessario o lascia il disinserimento bit. Impostare il bit raddoppia re si aggiunge 1, lasciarlo disinserito raddoppia.


4

Gelatina , 31 byte

S=³
3RUµḣ3S;µ<³Ạµ¿µŒPÇÐfṀe@ЀµḄ

Provalo online!

Sono quasi certo che ci sia un modo MOLTO più breve per raggiungere questo obiettivo in Jelly.

Come?

S=³ - Link 1, compare sum to input: list
S   - sum
  ³ - 3rd command line argument which is 1st program argument.
 =  - equal?

3RUµḣ3S;µ<³Ạµ¿µŒPÇÐfṀe@ЀµḄ - Main link: n
3RU                         - range(3) upended -> [3,2,1]
   µ    µ   µ¿              - while
         <³                 - less than input (vectorises)
           Ạ                - all?
    ḣ3S;                    -     head(3), sum, and concatenate
                                  [3,2,1] -> [6,3,2,1] -> [11,6,3,2,1] -> ...
              µ             - monadic chain separation, call the result x
               ŒP           - power set of x - e.g. for [6,3,2,1] -> [[],[6],[3],[2],[1],[6,3],[6,2],[6,1],[3,2],[3,1],[2,1],[6,3,2],[6,3,1],[6,2,1],[3,2,1],[6,3,2,1]]
                  Ðf        - filter keep
                 Ç          -     last link (1) as a monad (those that sum to the input)
                    Ṁ       - maximum (e.g. an input of 63 would yield [[37,20,6],[37,20,3,2,1]], the maximum of which is [37,20,6], the one with the largest numbers used)
                         µ  - monadic chain separation (to have x as the right argument below)
                     e@Ѐ   - exists in with reversed arguments mapped over x (e.g. [37,20,6] with x = [68,37,20,11,6,3,2,1] yields [0,1,1,0,1,0,0,0])
                          Ḅ - convert from binary to integer.        

4

Perl 6 , 93 91 byte

-2 byte grazie a b2gills

{my@f=1,2,3,*+*+*...*>$^n;sum @f».&{$_~~any first *.sum==$n,@f.combinations}Z*(2 X**^∞)}

Come funziona

  • Innanzitutto, genera la sequenza 1-2-3-Tribonacci fino al primo elemento più grande dell'input:

    my @f = 1, 2, 3, *+*+* ... * > $^n;
  • Sulla base di ciò trova il sottoinsieme della sequenza che si aggiunge all'input:

    first *.sum==$n, @f.combinations
  • Sulla base di ciò costruisce un elenco di booleani specificando se ogni elemento della sequenza fa parte della somma:

    @f».&{$_~~any ...}
  • E infine interpreta quell'elenco di valori True = 1, False = 0 come base 2 e lo restituisce come un numero (base 10):

    sum ... Z* (2 X** ^∞)

1
Puoi accorciarlo usando *>$^ne .sum==$n. Anche lo spazio non è necessario tra mye@f
Brad Gilbert b2gills

3

JavaScript (ES6), 61 60 byte

n=>(g=(x,y,z)=>(n>x&&g(y,z,x+y+z)*2)+!(n<x||![n-=x]))(1,2,3)

Calcola i numeri 1-2-3-Tribonacci fino a quando non raggiunge il numero originale, quindi man mano che la ricorsione si svolge, cerca di sottrarre ciascuno a turno, raddoppiando il risultato mentre procede.

Modifica: salvato 1 byte grazie a @Arnauld.


Wow! Molto bella. Potrebbe n=>(g=(x,y,z)=>(n>x&&g(y,z,x+y+z)*2)+!(n<x||![n-=x]))(1,2,3)salvare un byte?
Arnauld,

@Arnauld stavo cercando qualcosa usando n<x||ma questo ![]è solo geniale.
Neil

2

Lotto, 151 148 145 byte

@set/ar=0,n=%1
@call:c 3 2 1
@echo %r%
@exit/b
:c
@set/as=%1+%2+%3
@if %n% gtr %3 call:c %s% %*
@set/ar*=2
@if %n% geq %3 set/an-=%3,r+=1

Porta della mia risposta JavaScript. Modifica: ho salvato 3 byte passando i miei argomenti di subroutine in ordine inverso e altri 3 byte usando i singoli @s su ogni riga anziché @echo off.


2

Gelatina , 19 18 17 byte

Ḣx3+
BÇL¡2ị
²Ç€»ċ

Provalo online!

sfondo

Invece di provare a convertire un numero intero in 1,2,3-Tribonacci base, quindi da binario a intero, faremo il contrario: convertire interi in binario, quindi da 1,2,3-Trionacci base in intero e restituire il più alto che corrisponde all'input. Questo è facilmente realizzabile.

Esemplificeremo il processo per l'ingresso 63 , in particolare il passaggio in cui 104 viene testato. In binario, dalla cifra più significativa a quella meno significativa, 104 è uguale a

 1  1  0  1  0  0  0
37 20 11  6  3  2  1

dove la seconda riga rappresenta i valori posizionali di quelle cifre.

Possiamo estendere la sequenza 1,2,3-Tribonacci a destra, osservando che le cifre aggiunte sono conformi alla stessa formula ricorsiva. Per tre cifre, questo dà

 1  1  0  1  0  0  0  0  0  0
37 20 11  6  3  2  1  0  1  0

Ora, per calcolare il valore del numero 1,2,3-Tribonacci di base, possiamo usare la formula ricorsiva. Poiché ogni numero è la somma dei tre numeri alla sua destra (nella tabella sopra), possiamo rimuovere la prima cifra e aggiungerla alle prime tre cifre dell'array rimanente. Dopo 7 passaggi, che equivale al numero di cifre binarie di 104 , raramente restiamo con solo tre cifre.

 1  1  0  1  0  0  0  0  0  0
37 20 11  6  3  2  1  0  1  0

    2  1  2  0  0  0  0  0  0
   20 11  6  3  2  1  0  1  0

       3  4  2  0  0  0  0  0
      11  6  3  2  1  0  1  0

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

            12 10  7  0  0  0
             3  2  1  0  1  0

               22 19 12  0  0
                2  1  0  1  0

                  41 34 22  0
                   1  0  1  0

                     75 63 41
                      0  1  0

Ora, poiché la prima e l'ultima cifra rimanente hanno entrambe un valore posizionale 0 , il risultato è la cifra centrale, ovvero 63 .

Come funziona

²Ç€»ċ   Main link. Argument: n

²       Yield n². Since 1.839² = 3.381921 > 2, the range [1, ..., n²] will contain
        the answer. Better bounds, at the cost of additional bytes are possible.
 Ç€     Map the the second helper link over [1, ..., n²].
   »    Take the maximum of n and each result.
    ċ   Count the occurrences of n.


BÇL¡2ị  Second helper link. Left argument: k. Right argument: n

B       Convert k to binary. Let's call the result A.
  L     Length; count the number of binary digits. Let's call the result l.
 Ç ¡    Apply the first helper link l times to A.
    2ị  Retrieve the second element.


Ḣ×3+    First helper link. Argument: A (array)

Ḣ       Head; pop and yield the first element of A.
 x3     Repeat it thrice.
   +    Add the result, component by component, to the beheaded A.

2

Jelly ( fork ), 17 16 byte

ḣ3S;µ¡
3RṚdzæFṪḄ

Salvato 1 byte grazie a @Dennis che l'ha giocato senza nemmeno eseguirlo.

Questo si basa su un fork di Jelly in cui sto ancora deludentemente lavorando all'implementazione di un efficiente atomizzatore Frobenius. Per coloro che sono interessati, vorrei abbinare la velocità di Mathematica FrobeniusSolvee per fortuna c'è una spiegazione del loro metodo nel documento "Fare il cambiamento e trovare rimpiazzi: bilanciare uno zaino" di Daniel Lichtblau.

Spiegazione

ḣ3S;µ¡  Helper link. Input: a list
    µ   Create monadic chain
ḣ3        Take the first 3 items
  S       Sum
   ;      Prepend to the list
     ¡  Repeat it n (initial argument from main) times

3RṚdzæFṪḄ  Main link. Input: integer n
3          The constant 3
 R         Range. Makes [1, 2, 3]
  Ṛ        Reverse. Makes [3, 2, 1]
   Ç       Call the helper link on that list.
           Generates the first (n+3) 123-Tribonacci values in reverse
    ³      Get n
     æF    Frobenius solve for n using the first n 123-Tribonacci values in reverse
       Ṫ   Tail. Take the last value. The results of Frobenius solve are ordered
           where the last result uses the least
        Ḅ  Unbinary. Convert digits from base 2 to base 10

3
Sai che ti stai addentrando nel golf del codice quando usi le forchette di superesolang.
Addison Crump

Funzionerebbe ḣ3S;µ¡¶3RṚdzæFṪḄ? Non ho il fork installato, quindi non posso provare.
Dennis,

@Dennis Che sta prendendo input da stdin non argomenti, giusto? Ho avuto problemi nell'uso degli argomenti e mi sono reso conto che ha funzionato diversamente.
miglia

No, dovrebbero essere ancora argomenti. ³fa riferimento al primo argomento.
Dennis,

@Dennis Nvm, funziona con argomenti, il mio jelly.pyaveva alcune altre cose dopo l'ultimo commit.
miglia

1

dc , 110 102 byte

?se1sa2sb3sc_1sf[laddSdlbdsalcdsb++sclf1+sfle>y]dsyx0sk[lk2lf^+skler-se]sr[Lddle!<rlf1-dsf0!>z]dszxlkp

Beh, sembra che le grandi menti non pensano allo stesso modo. Apparentemente, l'algoritmo che mi è venuto in mente per aggirare i limiti dcè coincidente con lo stesso identico a quello usato nella risposta di @LliwTelrac. Interessante.

Provalo online!



1

utility bash + BSD (OS X, ecc.), 53 byte

jot $[2#$1**4]|egrep -v '[2-9]|11(1|$)'|sed $[2#$1]!d

utility bash + GNU (funziona anche con BSD), 59 byte

seq -f2o%.fp $[2#$1**2]|dc|egrep -v '11(1|$)'|sed $[2#$1]!d

Ingresso e uscita in entrambi i precedenti sono in binario.


Prova la versione GNU su TIO. (L'esempio collegato mostra l'input di 111111, che è 63 in binario, e l'output di 1101000, che è 104 in binario.)

Non penso che TIO offra un'opzione BSD, ma se hai un Mac disponibile, puoi provarli entrambi. (Il programma a 59 byte è molto più veloce del programma a 53 byte.)


Sfortunatamente, seqnon può essere semplicemente inserito nella soluzione BSD al posto di jot, poiché il formato di output per seqè diverso per output superiori a 999999. (Questo inizia a essere un problema per gli input intorno a 32, poiché 32 ^ 4> 1000000.)

È possibile sostituire jotsopra con seq -f%.fper farlo funzionare con le utility GNU, ma per gli stessi 59 byte, è possibile utilizzare la soluzione GNU sopra, che è molto più veloce.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.