Apenas por interesse, tentei resolver um problema da categoria "Recente" do Projeto Euler ( sequência Digit Sum ). Mas não consigo pensar em uma maneira de resolver o problema com eficiência. O problema é o seguinte (na sequência de perguntas original tem duas no início, mas não altera a sequência):
A sequência da soma dos dígitos é 1,2,4,8,16,23,28,38,49 .... onde o termo da sequência é a soma dos dígitos que a precedem na sequência. Encontre o termo da sequência.
A solução ingênua não pode ser implementada porque leva muito tempo. Tentei reduzir o problema a um caso de exponenciação da matriz (que levaria um tempo ), mas não consegui criar uma recorrência tão adequada aos critérios lineares, pois a recorrência para esta sequência é bastante peculiar. Pode-se ver que a sequência é governada pela recorrência:
onde é termo da sequência é uma função que, quando recebe um número natural como entrada, retorna a soma dos dígitos do número (por exemplo, ). Minha segunda abordagem foi tentar encontrar algum padrão na sequência. Pode-se observar que os primeiros termos da sequência podem ser escritos como
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 ) ) ) )
A partir do padrão acima, torna-se que termo da sequência pode ser gerado pelo seguinte método:
- Write é com o símbolo disso entre eles.
- Deixando o primeiro , aplique a função nos próximos termos, depois nos próximos termos, depois nos próximos termos e assim por diante.
- Em seguida, aplique o método acima recursivamente nos argumentos de cada função aplicada.
por exemplo, se n = 3, realizamos as seguintes manipulações:
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 ) ) )
Pela programação dinâmica, posso gerar o termo usando o método acima no tempo , que novamente não é melhor que a solução ingênua. O ( l o g ( 2 10 15 ) )
EDIT 1
Outra coisa que pode ser observada é que . Por exemplo . Mas sou incapaz de fazer uso deste ponto. Tentei novamente encontrar uma relação de recorrência linear (para exponenciação da matriz), mas não consigo encontrá-la.d ( a 6 ) = d ( 23 ) = d ( 32 ) = 5
EDIT 2
A seguir, é apresentado o gráfico quando a sequência é plotada para um intervalo menor (os primeiros termos da sequência são plotados).
PS: Eu sei que não é aconselhável pedir soluções ao Project Euler. Mas eu só quero uma nova direção ou uma dica, pois tenho andado em círculos nos últimos dias. Se isso também é inaceitável, posso remover a pergunta, se sugerido.
fonte
You are given a106 = 31054319.
no problema original de Euler é uma dica.Respostas:
Sua sequência é descrita em oeis.org/A004207 como a soma dos dígitos. Existem alguns pontos positivos, como a sequência mod 9 tem padrão de repetição , compartilha raízes digitais com oeis.org/A065075 e oeis.org/A001370 . Se essas propriedades forem úteis, é um problema aberto (porque não existe uma equação de forma fechada para o número). n - t h( 1 , 2 , 4 , 8 , 7 , 5 )∞ n - t h
Há algumas propriedades dessa sequência que vale a pena mencionar:n - t h
Quando você calcula o número, é necessário armazenar apenas o contador (para saber qual era o número) e o próprio número. Para reiniciar, não é necessário mais nada, pois o próximo número é o número atual + soma dos dígitos.
Seguindo algumas etapas para garantir a velocidade, é bom colocar números em um array, evitando cálculos ingênuos de mod e div, que são caros. Isso acelera constantemente, mas, às vezes, isso importa.
Desde o ponto inicial, você pode calcular o próximo e o próximo, e funciona até certo ponto, esse mesmo ponto é o número de dígitos alterados.
O que é mais importante, os padrões estão mudando com o aumento dos números.
As somas de dígitos são pequenas em comparação com os próprios números; portanto, apenas a parte do número será alterada na maioria das operações.
Então, o que realmente podemos armazenar em cache?
Sabemos que, com dois números com a mesma soma de dígitos, a adição para obter o próximo número será a mesma. E o próximo?
sasha
Alerta de spoiler, abaixo está um padrão de cache bastante explícito
Depende de condições adicionais, como os números que não mudam na corrida , chamarei de turno , começando o valor como início .
Fazendo uma execução arbitrária , como , e começando de a , podemos armazenar em cache todos os padrões do ponto de partida até , contar o número de elementos (para saber como lidar com o contador, necessário para fornecer um número ) e memorize-o. 0 9 100 n - t h100 0 0 9 100 n - t h
Está bem. Até agora, qualquer início é coberto, o que muda além de ? Infelizmente, esses padrões param de funcionar, porque se você tentar de tornando o início igual a , o próximo número será calculado perfeitamente, mas o segundo será interrompido. 100 1100
100 1
Aqui, temos que cobrir o turno definido como e iniciar o definido como . Também significa calcular tabelas para diferentes turnos . 01 0 0
Nós realmente precisamos calcular todos eles ? Não, realmente não.1 , 2 , 4 , 8
Parte das tabelas é apenas mais um item inicial.
Por exemplo, começando de fornece a mesma sequência deslocada. Então, precisamos calcular o cache mais longo? Não, calculamos isso para alterar as mudanças e realizar outra execução , economizando muita memória.
Agora, quando a tabela é coberta, começamos a partir da configuração inicial, selecionamos soma da tabela, adicionamos contador e vemos que: de chegamos a , atualizamos variáveis e pulamos para , repetindo as etapas -> -> -> -> -> -> -> . Está bem. E agora? 101 218 305 406 517 607 719 805 904 10031 101 218 305 406 517 607 719 805 904 1003
Podemos continuar até que o turno seja superior ao calculado.100 , 1000 , 10000 , 100000 , 1000000 ...
100
Indo além, podemos criar mais execuções rapidamente, pré-calcular execuções maiores ou observar outros padrões (como podemos parcialmente reutilizar as tabelas já calculadas).
Dê uma olhada em diferentes turnos como todos eles dão a mesma execução, sendo o mesmo ambiente para somas de dígitos, portanto, podemos usar as mesmas tabelas. Fazer tabelas maiores que elementos acelera o processo, fazendo saltos maiores ao mesmo tempo.100
fonte
Como você pediu "uma nova direção ou uma dica" e não sei a resposta, deixarei isso aqui, espero que seja útil. algumas ideias:
Faz sentido que haja um padrão 9, já que
O que você pode provar por indução.
Isso significa que todos os números são congruentes com a soma dos dígitos mod 9.
Além disso,uman= d( umn)mod9⟹
Se continuarmos expandindo essa recorrência, obtemos
O que explica o padrão mod 9.
Também nos dá . A cada iteração, obtemos uma lacuna divisível por 9. Qual a largura dessas lacunas?uman= 9 k + 2n
Aqui está um pouco abaixo do código geral:
O enredo (para os 100 primeiros) parece exponencial, mas não acho que seja perfeito.
Aqui está a saída de
A última coisa que tenho é que parece que se você soma os dígitos de um número e depois soma os dígitos do número resultante e repita isso, você finalmente obtém esse número mod 9.
Faz sentido, dado o fato acima, sobre potências de 10 mod 9.
No entanto, fornece uma sequência interessante de números.
Edit: Aparentemente, isso é chamado de "raiz digital".
fonte