Somme convergenti di una sequenza frattale


16

sfondo

Una sequenza frattale è una sequenza di numeri interi in cui è possibile rimuovere la prima occorrenza di ogni numero intero e finire con la stessa sequenza di prima.

Una sequenza molto semplice si chiama parafrasi di Kimberling . Inizi con i numeri naturali positivi:

1, 2, 3, 4, 5, 6, 7, 8, 9, ...

Quindi riffle in alcuni spazi vuoti:

1, _, 2, _, 3, _, 4, _, 5, _, 6, _, 7, _, 8, _, 9, ...

E quindi riempi ripetutamente gli spazi vuoti con la sequenza stessa (compresi gli spazi vuoti):

1, 1, 2, _, 3, 2, 4, _, 5, 3, 6, _, 7, 4, 8, _, 9, ...
1, 1, 2, 1, 3, 2, 4, _, 5, 3, 6, 2, 7, 4, 8, _, 9, ...
1, 1, 2, 1, 3, 2, 4, 1, 5, 3, 6, 2, 7, 4, 8, _, 9, ...
1, 1, 2, 1, 3, 2, 4, 1, 5, 3, 6, 2, 7, 4, 8, 1, 9, ...

Questa è la nostra sequenza frattale! Ora prendiamo le somme parziali:

1, 2, 4, 5, 8, 10, 14, 15, 20, 23, 29, 31, 38, 42, 50, 51, 60, ...

E se ripetessimo questo processo? "Frattalizza" la nuova sequenza (ovvero le somme parziali ottenute dai passaggi precedenti):

1, _, 2, _, 4, _, 5, _, 8, _, 10, _, 14, _, 15, _, 20, _, 23, ...
1, 1, 2, _, 4, 2, 5, _, 8, 4, 10, _, 14, 5, 15, _, 20, 8, 23, ...
1, 1, 2, 1, 4, 2, 5, _, 8, 4, 10, 2, 14, 5, 15, _, 20, 8, 23, ...
1, 1, 2, 1, 4, 2, 5, 1, 8, 4, 10, 2, 14, 5, 15, _, 20, 8, 23, ...
1, 1, 2, 1, 4, 2, 5, 1, 8, 4, 10, 2, 14, 5, 15, 1, 20, 8, 23, ...

E prendere di nuovo le somme parziali:

1, 2, 4, 5, 9, 11, 16, 17, 25, 29, 39, 41, 55, 60, 75, 76, 96, ...

Risciacqua, ripeti. Si scopre che questo processo converge. Ogni volta che ripeti questo processo, un prefisso più grande della sequenza rimarrà fisso. Dopo un numero infinito di iterazioni, si finirà con OEIS A085765 .

Curiosità: questo processo convergerebbe nella stessa sequenza anche se non iniziassimo dai numeri naturali fintanto che inizia la sequenza originale 1. Se la sequenza originale inizia con un'altra x, otterremmox*A085765 invece.

La sfida

Dato un numero intero positivo N, emette ilN elemento th della sequenza convergente.

È possibile scrivere un programma o una funzione, prendendo l'input tramite STDIN (o l'alternativa più vicina), l'argomento della riga di comando o l'argomento della funzione e producendo il risultato tramite STDOUT (o l'alternativa più vicina), il valore di ritorno della funzione o il parametro della funzione (out).

È possibile scegliere se l'indice Nè basato su 0 o 1.

Casi test

La sequenza inizia con:

1, 2, 4, 5, 9, 11, 16, 17, 26, 30, 41, 43, 59, 64, 81, 82, 108, 117, 147, 151, 192, 203, 246, 248, 307, 323, 387, 392, 473, 490, 572, 573, 681, 707, 824, 833, 980, 1010, 1161, 1165, 1357, 1398, 1601, 1612, 1858, 1901, 2149, 2151, 2458, 2517

Quindi l'input 5dovrebbe produrre output 9.

Ecco un'implementazione di riferimento ingenua di CJam che genera i primi Nnumeri (dati Nsu STDIN). Nota che il tuo codice dovrebbe restituire solo l' Nelemento th, non l'intero prefisso.


Quindi, solo controllando: stiamo producendoN il termine A085765 , giusto?
GamrCorps l'

@GamrCorps Sì.
Martin Ender,

Risposte:


7

CJam ( 23 22 byte)

Le somme parziali sono date agli indici pari della sequenza frattale, che è A086450 . La ricorrenza data come definizione di A086450 è la base per queste implementazioni.

Utilizzando uno "stack" esplicito (tra virgolette perché non è LIFO):

{),){2md~)\),>+$)}h+,}

Demo online

Dissezione

{         e# Anonymous function body; for clarify, pretend it's f(x)
          e# We use a stack [x_0 ... x_i] with invariant: the result is sum_j f(x_j)
  ),      e# Initialise the stack to [0 ... x]
  )       e# Uncons x, because our loop wants one value outside the stack
  {       e# Loop. Stack holds [x_0 ... x_{i-1}] x_i
    2md   e# Split x_i into (x_i)/2 and (x_i)%2
    ~)\   e# Negate (x_i)%2 and flip under (x_i)/2
    ),>   e# If x_i was even, stack now holds [x_0 ... x_{i-1}] [0 1 ... (x_i)/2]
          e# If x_i was odd, stack now holds [x_0 ... x_{i-1}] [(x_i)/2]
    +     e# Append the two arrays
    $     e# Sort to get the new stack
    )     e# Uncons the greatest element in the new stack
  }h      e# If it is non-zero, loop
          e# We now have a stack of zeroes and a loose zero
  +,      e# Count the total number of zeroes, which is equivalent to sum_j f(0)
}

A 23 byte c'è un approccio molto più efficiente, con memoria:

{2*1a{2md~)\){j}%>:+}j}

Demo online


1
Sono sicuro che ci sono alcune lingue in cui sarebbe più breve da implementare f(0) = 1; f(n) = f(n/2) + (n % 2 ? 0 : f(n-2)); return f(2*x), ma non riesco a trovare un modo per risparmiare con quell'approccio in CJam.
Peter Taylor,

9

Python 2, 55 49 42

Non ho idea di cosa stia succedendo, ma sembra difficile battere la formula di Maple dalla pagina OEIS. Questo utilizza l'indicizzazione basata su 0.

f=lambda n,t=0:n<1or f(n/2,n%2)-~-t*f(n-1)

Grazie a @PeterTaylor per -6 byte.


È facile da ottimizzare con 6 caratteri se non ti interessano le prestazioni. Le parti dopo la prima orsono effettivamente g(n,1) = f(n/2,n%2); g(n,0) = f(n-1) + g(n,1); così puoi tirare fuori il comune g(n,1)per otteneref=lambda n,t=0:n<1or f(n/2,n%2)+0**t*f(n-1)
Peter Taylor

3

Haskell, 65 anni

s l=[0..]>>=(\i->[l!!i,s l!!i])
r=1:(tail$scanl1(+)$s r)
f n=r!!n

2

Modelli considerati dannosi , 124

Fun<If<A<1>,Add<Ap<Fun<Ap<If<Sub<A<1>,Mul<I<2>,Div<A<1>,I<2>>>>,A<0>,A<0,1>>,Div<A<1>,I<2>>>>,A<1>>,Ap<A<0>,Sub<A<1>,T>>>,T>>

Questa è una funzione anonima. È più o meno lo stesso di mia risposta Python alla formula Maple nella pagina OEIS, tranne per il fatto che non ho implementato il modulo, quindi ho dovuto usare nn / 2 * 2 invece di n% 2.

Allargato:

Fun<If<
    A<1>,
    Add<
        Ap<
            Fun<Ap<
                If<
                    Sub<
                        A<1>,
                        Mul<
                            I<2>,
                            Div<A<1>,I<2> >
                        >
                    >,
                    A<0>,
                    A<0,1>
                >,
                Div<A<1>,I<2>>
            >>,
            A<1>
        >,
        Ap<
            A<0>,
            Sub<A<1>, T>
        >
    >,
    T
>> 

2

Mathematica, 47 44 byte

If[#<1,1,#0[Floor@#/2]+(1-2#~Mod~1)#0[#-1]]&

0

Matlab 108 103

Sto usando il fatto che la serie desiderata è la somma parziale di https://oeis.org/A086450

Ma la complessità computazionale della mia implementazione è tutt'altro che ottimale, anche per questa semplice ricorrenza.

n=input('')+1;
z=zeros(1,n);z(1)=1;
for k=1:n;
z(2*k)=z(k);
z(2*k+1)=sum(z(1:k+1));
end;
disp(sum(z(1:n)))
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.