Genera n cifre della sequenza di Gijswijt


19

introduzione

La sequenza di Gijswijt ( A090822 ) è notoriamente davvero, VERAMENTE lenta. Illustrare:

  • I primi 3 appaiono nel nono termine (va bene).
  • Il primo 4 appare nel 220 ° termine (molto lontano, ma fattibile).
  • Il primo 5 appare (approssimativamente) al 10 ^ (10 ^ 23) esimo termine (solo no).
  • Nessuno sa davvero dove siano i primi 6 ... si sospetta che sia al ...

    2 ^ (2 ^ (3 ^ (4 ^ 5))) th termine.

Puoi presumere che non dovrai avere a che fare con un numero a due cifre.

La sequenza viene generata in questo modo:

  1. Il primo termine è 1.
  2. Ogni termine successivo indica la quantità di "blocchi" ripetuti precedenti (se sono presenti più "blocchi" ripetuti, viene utilizzata la quantità maggiore di blocchi ripetuti).

Per chiarire, ecco i primi termini.

1 -> 1, 1(un blocco ripetuto ( 1), quindi la cifra registrata è 1)

1, 1 -> 1, 1, 2(due blocchi ripetuti ( 1), quindi la cifra registrata è 2)

1, 1, 2 -> 1, 1, 2, 1(un blocco ripetuto ( 2o 1, 1, 2), quindi la cifra registrata è 1)

1, 1, 2, 1 -> 1, 1, 2, 1, 1 (hai avuto l'idea)

1, 1, 2, 1, 1 -> 1, 1, 2, 1, 1, 2

1, 1, 2, 1, 1, 2 -> 1, 1, 2, 1, 1, 2, 2(due blocchi ripetuti ( 1, 1, 2), quindi la cifra registrata è 2)

Compito

Il tuo compito è, come indicato nella domanda, generare n cifre della sequenza Gijswijt.

Istruzioni

  • L'input sarà un numero intero n.
  • Il codice può generare le cifre in qualsiasi forma (un elenco, più uscite, ecc.).

Questo è il codice golf, quindi vince il codice più breve in byte.

Risposte:


7

Pyth, 25 22 21 byte

t_u+eSmtfxG*Td1._GGQN

OP ha confermato che dobbiamo gestire solo numeri a una cifra. Ciò ha permesso di memorizzare l'elenco come una stringa di cifre. -> 3 byte salvati

Provalo online: dimostrazione

Spiegazione:

t_u+...GQN      implicit: Q = input number
         N      start with the string G = '"'
  u     Q       do the following Q times:
    ...            generate the next number
   +   G           and prepend it to G
 _              print reversed string at the end
t               remove the first char (the '"')

Ed ecco come posso generare il prossimo numero:

eSmtfxG*Td1._G
           ._G    generate all prefixes of G
  m               map each prefix d to:
    f     1          find the first number T >= 1, so that:
       *Td              d repeated T times
     xG                 occurs at the beginning of G
 S                  sort all numbers
e                   take the last one (maximum)   

21 byte con elenchi

_u+eSmhhrcGd8SlGGtQ]1

Provalo online: dimostrazione

Usa le stesse idee di Martin e Peter. Ad ogni passo ho diviso la stringa in pezzi di lunghezza 1, pezzi di lunghezza 2, ... Quindi li codifico per lunghezza e li utilizzo e uso la prima corsa massima come numero successivo.

20 byte con stringhe

t_u+eSmhhrcGd8SlGGQN

Provalo online: dimostrazione

Combina le idee dei due codici sopra.


1
Grazie per avermi insegnato. Ho sempre dimenticato la ._funzione e altre funzioni utili in Pyth.
Leaky Nun,

Personalmente mi è piaciuta di più la soluzione originale, ma eh.
clismique,

@Jakube Ah. Posso dare un'occhiata? Se sì, allora grazie!
clismique,

@DerpfacePython È stato in grado di golf un byte aggiuntivo alla mia soluzione originale. Ho anche pubblicato la soluzione di codifica run-length basata su Martin e quindi sono stato in grado di combinare i due approcci per generare una soluzione di 20 byte.
Jakube,

5

CJam, 33 31 30 27 byte

Grazie a Peter Taylor per aver salvato 1 byte.

1sri({),:)1$W%f/:e`$W=sc+}

Provalo qui.

Spiegazione

1s      e# Initialise the sequence as "1".
ri(     e# Read input N and decrement.
{       e# For each I from 0 to N-1...
  )     e#   Increment to get I from 1 to N.
  ,     e#   Turn into a range [0 1 ... I-1].
  :)    e#   Increment each element to get [1 2 ... I].
  1$    e#   Copy sequence so far.
  W%    e#   Reverse the copy.
  f/    e#   For each element x in [1 2 ... I], split the (reversed) sequence
        e#   into (non-overlapping) chunks of length x. These are the potentially
        e#   repeated blocks we're looking for. We now want to find the splitting
        e#   which starts with the largest number of equal blocks.
  :e`   e#   To do that, we run-length encode each list blocks.
  $     e#   Then we sort the list of run-length encoded splittings, which primarily
        e#   sorts them by the length of the first run.
  W=    e#   We extract the last splitting which starts with the longest run.
  sc    e#   And then we extract the length of the first run by flattening
        e#   the list into a string and retrieving the first character.
  +     e#   This is the new element of the sequence, so we append it.
}/

+1 per :) (5 in più per andare ...)
Leaky Nun

5

CJam ( 30 29 27 24 byte)

'1ri{{)W$W%/e`sc}%$W>+}/

Demo online

Questo è uno sforzo congiunto con Martin.

  • L'uso intelligente della codifica run-length (e` ) per identificare le ripetizioni è di Martin
  • Quindi è l'uso di W$ per semplificare la gestione dello stack
  • Ho eliminato un paio di operazioni di incremento / decremento usando il case $W>+speciale, come spiegato nella dissezione di seguito

Il mio primo approccio a 30 byte:

1ari{,1$f{W%0+_@)</{}#}$W>+}/`

Demo online

Dissezione

1a        e# Special-case the first term
ri{       e# Read int n and iterate for i=0 to n-1
  ,1$f{   e#   Iterate for j=0 to i-1 a map with extra parameter of the sequence so far
    W%0+  e#     Reverse and append 0 to ensure a non-trivial non-repeating tail
    _@)</ e#     Take the first j+1 elements and split around them
    {}#   e#     Find the index of the first non-empty part from the split
          e#     That's equivalent to the number of times the initial word repeats
  }
  $W>+    e#   Add the maximal value to the sequence
          e#   NB Special case: if i=0 then we're taking the last term of an empty array
          e#   and nothing is appended - hence the 1a at the start of the program
}/
`         e# Format for pretty printing

3

Haskell, 97 byte

f 1=[1]
f n|x<-f$n-1=last[k|k<-[1..n],p<-[1..n],k*p<n,take(k*p)x==([1..k]>>take p x)]:x
reverse.f

La terza riga definisce una funzione anonima che accetta un numero intero e restituisce un elenco di numeri interi. Guardalo in azione.

Spiegazione

La funzione helper fcostruisce la sequenza al contrario, verificando ricorsivamente se la sequenza precedente inizia con un blocco ripetuto. kè il numero di ripetizioni ed pè la lunghezza del blocco.

f 1=[1]                                   -- Base case: return [1]
f n|x<-f$n-1=                             -- Recursive case; bind f(n-1) to x.
  last[k|k<-[1..n],                       -- Find the greatest element k of [1..n] such that
  p<-[1..n],                              -- there exists a block length p such that
  k*p<n,                                  -- k*p is at most the length of x, and
  take(k*p)x                              -- the prefix of x of length p*k
    ==                                    -- is equal to
  ([1..k]>>take p x)                      -- the prefix of length p repeated k times.
  ]:x                                     -- Insert that k to x, and return the result.
reverse.f                                 -- Composition of reverse and f.


1

Retina , 66 60 byte

+1`((\d+)?(?<1>\2)*(?<!\3(?>(?<-1>\3)*)(?!.*\2)(.+)))!
$1$#1

L'input è un numero intero unario che utilizza ! come cifra (sebbene ciò possa essere modificato in qualsiasi altro carattere non numerico). L'output è semplicemente una stringa di cifre.

Provalo online! (In alternativa, per comodità ecco una versione che accetta input decimali. )

A scopo di test, questo può essere velocizzato molto con una piccola modifica, che consente di testare l'ingresso 220 in meno di un minuto:

+1`((\d+)?(?<1>\2)*(?=!)(?<!\3(?>(?<-1>\3)*)(?!.*\2)(.+)))!
$1$#1

Provalo online! ( Versione decimale. )

Se vuoi testare numeri ancora più grandi, è meglio dargli solo un input massiccio e mettere un :dopo l'iniziale +. In questo modo Retina stampa la sequenza corrente ogni volta che termina di calcolare una nuova cifra (con tutte le cifre una alla volta).

Spiegazione

La soluzione consiste in una singola sostituzione regex, che viene applicata ripetutamente all'input fino a quando il risultato non smette di cambiare, cosa che in questo caso accade perché la regex non corrisponde più. +L'all'inizio introduce questo ciclo. La 1è un termine che indica Retina solo sostituire la prima partita (questo vale solo per la prima iterazione). In ogni iterazione, lo stage sostituisce uno! (da sinistra) con la cifra successiva della sequenza.

Come al solito, se hai bisogno di un primer sui gruppi di bilanciamento ti rimando alla mia risposta SO .

Ecco una versione annotata della regex. Si noti che l'obiettivo è acquisire il numero massimo di blocchi ripetuti nel gruppo 1.

(                 # Group 1, this will contain some repeated block at the end
                  # of the existing sequence. We mainly need this so we can
                  # write it back in the substitution. We're also abusing it
                  # for the actual counting but I'll explain that below.
  (\d+)?          # If possible (that is except on the first iteration) capture
                  # one of more digits into group 2. This is a candidate block
                  # which we're checking for maximum repetitions. Note that this
                  # will match the *first* occurrence of the block.
  (?<1>\2)*       # Now we capture as many copies of that block as possible
                  # into group 1. The reason we use group 1 is that this captures
                  # one repetition less than there is in total (because the first
                  # repetition is group 2 itself). Together with the outer
                  # (unrelated) capture of the actual group one, we fix this
                  # off-by-one error. More importantly, this additional capture
                  # from the outer group isn't added until later, such that the
                  # lookbehind which comes next doesn't see it yet, which is
                  # actually very useful.
                  # Before we go into the lookbehind note that at the end of the
                  # regex there's a '!' to ensure that we can actually reach the
                  # end of the string with this repetition of blocks. While this 
                  # isn't actually checked until later, we can essentially assume
                  # that the lookbehind is only relevant if we've actually counted
                  # repetitions of a block at the end of the current sequence.

  (?<!            # We now use a lookbehind to ensure that this is actually the
                  # largest number of repetitions possible. We do this by ensuring
                  # that there is no shorter block which can be matched more
                  # often from the end than the current one. The first time this
                  # is true (since, due to the regex engine's backtracking rules,
                  # we start from longer blocks and move to shorter blocks later),
                  # we know we've found the maximum number of repetitions.
                  # Remember that lookbehinds are matched right-to-left, so
                  # you should read the explanation of the lookbehind from
                  # bottom to top.
    \3            # Try to match *another* occurrence of block 3. If this works,
                  # then this block can be used more often than the current one
                  # and we haven't found the maximum number of repetitions yet.
    (?>           # An atomic group to ensure that we're actually using up all
                  # repetitions from group 1, and don't backtrack.
      (?<-1>\3)*  # For each repetition in group 1, try to match block 3 again.
    )
    (?!.*\2)      # We ensure that this block isn't longer than the candidate
                  # block, by checking that the candidate block doesn't appear
                  # right of it.
    (.+)          # We capture a block from the end into group 3.
  )               # Lookbehind explanation starts here. Read upwards.
)
!                 # As I said above, this ensures that our block actually reaches
                  # the end of the string.

Alla fine, dopo aver fatto tutto ciò, riscriviamo $1(eliminando in tal modo il !) nonché il numero di acquisizioni nel gruppo con le $#1quali corrisponde al numero massimo di ripetizioni.


Perché Retina prende soluzioni unarie anziché numeri?
clismique,

@DerpfacePython Perché è più economico e consentito dal consenso . Sei libero di sovrascrivere specificando che l'input deve essere un numero decimale (nel qual caso sono felice di cambiare la soluzione).
Martin Ender,

Ah, grazie per il chiarimento. Solo per curiosità, però, puoi mettere (nei commenti) una risposta decimale? Se è così, grazie.
clismique,

@DerpfacePython Aggiunti collegamenti separati usando l'input decimale.
Martin Ender,

Spiegazione quando ho finito di giocare a golf?
CalculatorFeline

0

Rubino, 84 byte

La risposta di Retina mi ha ispirato a fare una soluzione basata su regex per trovare la sequenza migliore anziché in qualche modo contare le sequenze in un array, ma con meno genio (lookbehinds negativi con quantificatori non sembrano essere ammessi in Ruby, quindi dubito Potrei portare direttamente la risposta di Retina comunque)

->n{s='';n.times{s+=(1..n).map{|i|s=~/(\d{#{i}})\1+$/?$&.size/i: 1}.max.to_s};s[-1]}

Data una sequenza già generata s, esegue il mapping su tutto ida 1a s.lengthnstato utilizzato in questo caso per salvare byte da allora n>=s.length) e quindi utilizza questa regex per aiutare a calcolare il numero di ripetizioni di una sottosequenza con lunghezza i:

/(.{#{i}})\1+$/
/(                 # Assign the following to group 1
  .{#{i}}          # Match `i` number of characters
         )         # End group 1
          \1+      # Match 1 or more repetitions of group 1
             $/    # Match the end of string

Se viene trovata una corrispondenza di quella lunghezza, calcola il numero di ripetizioni dividendo la lunghezza della partita data $&per ila lunghezza della sottosequenza; se non viene trovata alcuna corrispondenza, viene considerata come 1. La funzione trova quindi il numero massimo di ripetizioni da questa mappatura e aggiunge quel numero alla fine della stringa.

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.