Come trovare in modo efficiente l'elemento della sequenza della somma delle cifre?


20

Appena per interesse ho cercato di risolvere un problema dalla categoria "Recenti" di Project Euler ( sequenza di cifre ). Ma non sono in grado di pensare a un modo per risolvere il problema in modo efficiente. Il problema è il seguente (nella sequenza di domande originale ne ha due all'inizio, ma non cambia la sequenza):

La sequenza della somma delle cifre è 1,2,4,8,16,23,28,38,49 .... dove il termine della sequenza è la somma delle cifre che la precedono nella sequenza. Trova il termine della sequenza. 10 15 t hnth1015th

La soluzione ingenua non può essere implementata perché richiede molto tempo. Ho cercato di ridurre il problema a un caso di esponenziazione della matrice (che richiederebbe tempo) ma non sono riuscito a trovare una tale ricorrenza che si adattava ai criteri lineari come la ricorrenza per questa sequenza è abbastanza strano. Si può vedere che la sequenza è governata dalla ricorrenza:O(log(1015))

an=an1+d(an1).....(1)

dove è termine della sequenza e è una funzione che quando viene dato un numero naturale come input restituisce la somma delle cifre del numero (es. ). Il mio secondo approccio è stato quello di cercare di trovare uno schema nella sequenza. Si può vedere che i primi termini della sequenza possono essere scritti comeannthdd(786)=21

   a_1 = 1  
   a_2 = 1 + d( 1 )
   a_3 = 1 + d( 1 ) + d( 1 + d( 1 ) )
   a_4 = 1 + d( 1 ) + d( 1 + d( 1 ) ) + d( 1 + d( 1 ) + d( 1 + d( 1 ) ) )
   a_5 = 1 + d( 1 ) + d( 1 + d( 1 ) ) + d( 1 + d( 1 ) + d( 1 + d( 1 ) ) ) + d( 1 +  d(  
   1 ) + d( 1 + d( 1 ) ) + d( 1 + d( 1 ) + d( 1 + d( 1 ) ) ) )

Dal modello sopra diventa che termine della sequenza può essere generato con il seguente metodo:nth

  1. Scrivi con il simbolo di aggiunta tra di loro.2n1 1
  2. Lasciando il primo , quindi applicare la funzione sui termini successivi, quindi sui termini 2 ^ {1} successivi, quindi sui termini 2 ^ {2} successivi e così via.1d202122
  3. Quindi applicare il metodo sopra ricorsivamente sugli argomenti di ciascuna funzione d applicata.

ad esempio se n = 3 eseguiamo le seguenti manipolazioni:

    1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
    1 + d( 1 ) + d( 1 + 1 ) + d( 1 + 1 + 1 + 1 )
    1 + d( 1 ) + d( 1 + d(1) ) + d( 1 + d( 1 ) + d( 1 +d( 1 ) ) )

Tramite la programmazione dinamica posso generare il termine usando il metodo sopra nel tempo , che di nuovo non è migliore della soluzione ingenua. O ( l o g ( 2 10 15 ) )nthO(log(21015))

EDIT 1
Un'altra cosa che si può osservare è che . Ad esempio . Ma non sono in grado di sfruttare questo punto. Ho di nuovo provato a trovare una relazione di ricorrenza lineare (per esponenziazione di matrice), ma non riesco a trovarla.d ( a 6 ) = d ( 23 ) = d ( 32 ) = 5d(an)=d(2n1)d(a6)=d(23)=d(32)=5

MODIFICA 2

Di seguito è riportato il grafico quando la sequenza viene tracciata per un intervallo più piccolo ( vengono tracciati i primi termini della sequenza). 106inserisci qui la descrizione dell'immagine

PS: So che non è consigliabile chiedere soluzioni al Progetto Euler. Ma voglio solo una nuova direzione o un suggerimento, poiché mi sono spostato in cerchio negli ultimi giorni. Se anche questo è inaccettabile, posso rimuovere la domanda se suggerito.


1
Sento che You are given a106 = 31054319.nell'originale problema di Eulero è un suggerimento.
Filip Haglund,

@FilipHaglund che non è un suggerimento. Come solo con la forza bruta posso calcolare facilmente quel valore. È solo per verificare il tuo approccio.
sashas,

3
Anche su OEIS: oeis.org/A004207 .
Yuval Filmus,

@EvilJS sì, ho tracciato il grafico in modo estensivo che aumenta gradualmente in modo a zig zag. Potresti elaborare il tuo ultimo punto "" modelli di cache ... ".
sashas

Dato che modelli interessanti appaiono mod 9, succede qualcosa di interessante se osserviamo la sequenza mod 11 o mod 99? Il valore mod 11 può essere derivato dalla somma delle cifre indicizzate dispari e dalla somma delle cifre indicizzate pari. Il valore mod 99 può essere derivato dalla somma delle coppie di cifre adiacenti.
DW

Risposte:


4

La sequenza è descritta in oeis.org/A004207 come somma delle cifre. Ci sono alcuni punti positivi come la sequenza 9 ha un modello ripetitivo , condivide le radici digitali con oeis.org/A065075 e oeis.org/A001370 . Se queste proprietà sono utili è un problema aperto (perché non esiste un'equazione in forma chiusa per l' numero). n - t h(1,2,4,8,7,5)nth

Vi sono alcune proprietà di questa sequenza degne di nota:
quando si calcola l' numero, è necessario memorizzare solo il contatore (per sapere quale numero era) e il numero stesso. Per riavviare non è necessario altro, poiché il numero successivo è il numero corrente + somma delle sue cifre.nth

Adottare alcune misure per garantire la velocità all'inizio è bene mettere i numeri nell'array, evitando calcoli ing mod e div, che sono costosi. Questo accelera costantemente, ma a volte è importante.

Dal punto di partenza è possibile calcolare il prossimo e il successivo, e funziona fino a un certo punto, proprio questo è il numero di cifre che cambiano.
Ciò che è più importante, i modelli stanno cambiando con l'aumento dei numeri.
Le somme delle cifre sono piccole rispetto ai numeri stessi, quindi solo la parte del numero cambierà nella maggior parte delle operazioni.
Quindi cosa possiamo davvero memorizzare nella cache?

Sappiamo che con due numeri con la stessa somma di cifre l'aggiunta per ottenere il numero successivo sarà la stessa. E il prossimo?

sasha

Avviso spoiler, di seguito è riportato un pattern cache abbastanza esplicito

Dipende da condizioni aggiuntive, come i numeri che non cambiano durante la corsa , lo chiamerò shift , importo iniziale come inizio .

10009100nth

100
1001

Qui dobbiamo coprire shift impostato su e iniziare impostato su . Significa anche calcolare tabelle per turni diversi . 10

Dobbiamo davvero calcolarli tutti ? Non proprio no.
Parte delle tabelle è solo un altro elemento iniziale ulteriormente.
Ad esempio a partire da ottiene la stessa sequenza spostata. Quindi dobbiamo calcolare cache più lunghe? No, lo calcoliamo per spostare il cambio per riprendere un'altra corsa , quindi risparmierà molta memoria. 1,2,4,8

11012183054065176077198059041003



100,1000,10000,100000,1000000...
100


4

Dato che hai chiesto "una nuova direzione o un suggerimento" e non conosco la risposta, lascio questo qui, spero sia utile. qualche idea:

Ha senso che ci sarebbe un modello mod 9, da allora

k>1,kZ10k1mod9

Che puoi provare per induzione.

Ciò significa che tutti i numeri sono congruenti con la somma delle loro cifre mod 9.

Inoltre, an=d(an)mod9

an=an1+d(an1)=2d(an1)mod9

Se continuiamo ad espandere questa ricorrenza otteniamo

an=2nmod9

Il che spiega il modello mod 9.

Ci anche . Ogni iterazione otteniamo un divario che è divisibile per 9. Quanto sono ampie queste lacune?an=9k+2n

Ecco un po 'meno del codice generale:

import matplotlib.pyplot as plt
import numpy as np

#sum digits of n
def sum_digits(n):
    s = 0
    while n:
        s += n % 10
        n //= 10
    return s

#get the sequence to n digits
def calculate(n):
    retval = [1]
    for i in range(n):
        retval.append(retval[-1] + sum_digits(retval[-1]))
    return retval;

#empirically confirm that a_n = 2^n mod 9
def confirmPow2(a):
    count = 0
    for i in a[:10000]:
        if((i%9) != (2**count % 9)):
            print "false"
        count = count + 1

#find gaps divisible by 9 in a subset of a
def find9Gaps(a):
    count = 0
    S = []
    for i in a[:10000]:
         S.append(((2**count ) - i)/9)
         count = count + 1
    return S

#repeatedly sum the digits until they're less than 9...
#gives some interesting patterns
def repeatedDigitSum():
    for i in range(1000, 1100):
         print "=========for ",i
         while i > 9:
                 i = sum_digits(i)
                 print i 


a = calculate(10**6)
b = find9Gaps(a)
plt.plot(range(len(b[:100])), b[:100])
plt.show()

La trama (per i primi 100) sembra esponenziale, ma non credo sia perfetta.

trama per lacune

Ecco l'output di

>>> plt.plot(range(len(b[5:60])), np.log2(np.array(b[5:60])))
>>> plt.show()

trama logaritmica delle lacune

L'ultima cosa che ho è che sembra che se sommi le cifre di un numero, quindi sommi le cifre del numero risultante e ripeti questo, alla fine ottieni quel numero mod 9.

Ha senso dato il fatto sopra riguardo ai poteri di 10 mod 9.

nd(n)d(d(n))mod9

Dà comunque un'interessante sequenza di numeri.

Modifica: apparentemente questo si chiama "radice digitale".


1
È stato un po 'commentato almeno tre volte. Anche quando fai una trama che ti sembra esponenziale, forse dovresti usare il logaritmo, informarti sull'asse della scala? Se hai tracciato 10 ^ 16 termini leggibili, sarei davvero colpito.
Evil

Cosa è stato commentato 3 volte? La gente diceva che esisteva un "modello mod 9" ma mi sembrava che non fosse chiaro quale fosse. Ho appena esplorato e commentato quello che avevo, dal momento che non credo che sarò in grado di continuare a lavorare su questo. Ancora una volta, non ho una soluzione, ma la domanda non ha posto una domanda.
quietContest,

Aggiunta una trama del registro per ogni suggerimento di EvilJS, non posso tracciare una trama più grande perché le intorpidimenti si interrompono e davvero non ho tempo di continuare a perseguire questo problema
quietContest
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.