Q, 47 bytes
m:{*/1_-':|(0<){y-x x bin y}[*+60(|+\)\1 0]\x}
Teste
+(i;m'i:1 2 3 4 5 6 7 8 9 42 1000 12345)
leia-o como pares (i, mapa (m, i)), onde m é a função de cálculo ei os diferentes argumentos
escreve
1 1
2 2
3 3
4 3
5 5
6 5
7 10
8 8
9 8
42 272
1000 12831
12345 138481852236
Explicação
n funtion\arg
aplica function (function (function (... function (args))) n times (usa internamente tal recursão) e retorna a sequência de resultados. Calculamos os 60 primeiros itens da série fibonnaci como *+60(|+\)\1 0
. Nesse caso, a função é ( | +): + \ aplicado sobre uma sequência calcula somas parciais (ex + \ 1 2 3 é 1 3 6) e | inverte a seq. Portanto, cada 'iteração' calculamos somas parciais dos dois números anteriores de fibonacci e retornamos o parcial soma invertida 60(|+\)\1 0
gera as seqüências 1 0, 1 1, 2 1, 3 2, 5 3, 8 5, 13 8, 21 13, ...*+
aplicado sobre esse resultado flip (traspose) e pega o primeiro. 1 2 3 5 8 13 21 34 55 ..
(cond)function\args
aplica function (function (.. function (args))) enquanto cond true e retorna a sequência de resultados parciais
function[arg]
aplicado sobre uma função de mais de um argumento cria uma projeção (aplicação parcial)
Podemos dar um nome aos argumentos, mas os nomes implícitos são x, y, z
{y-x x bin y}[*+60(|+\)\1 0]
declara um lambda com args x, y com projeção parcial (arg x é uma série de fibonacci, calcula como * + 60 (| +) \ 1 0). x representam valores de fibonacci e y o número a processar. A pesquisa binária (bin) é usada para localizar o índice do maior número de fibonacci <= y ( x bin y
) e subtrair o valor correspondente de x.
Para calcular o produto a partir de resultados parciais, nós os revertemos e calculamos a diferença de cada par ( -':|
), descartamos o primeiro ( 1_
porque é 0) e multiplicamos por ( */
).
Se estamos interessados na soma acumulada, o código é o mesmo, mas com em +/
vez de */
. Também podemos usar qualquer outro operador diádico em vez de + ou *
Sobre eficiência de execução
Eu sei que neste concurso a eficiência não é um problema. Mas neste problema, podemos variar de custo linear a custo exponencial, por isso estou curioso.
Eu desenvolvi uma segunda versão (comprimento de 48 bytes, excluindo comentários) e repeti os casos de teste de bateria 1000 vezes nas duas versões.
f:*+60(|+\)\1 0;m:{*/1_-':|(0<){x-f f bin x}\x} /new version
o tempo de execução é: versão original 0'212 seg, nova versão 0'037 seg
A versão original calcula a série fibbonaci uma vez por aplicativo de função; nova versão calcula fibonacci apenas um.
Em ambos os casos, o cálculo da série de fibonacci usa recursão da cauda
2
pode ser decomposto como-1 + 3
. A afirmação correta do teorema de Zeckendorf é que um número de Fibonacci positivo pode ser decomposto exclusivamente como uma soma de números de Fibonacci não consecutivos com índice positivo.