Ir al contenido principal

Cadenas de sumas de factoriales de los dígitos

Dado un número n se considera la sucesión cuyo primer término es n y los restantes se obtienen sumando los factoriales de los dígitos del anterior. Por ejemplo, la sucesión que empieza en 69 es

    69
363600  (porque 6! + 9! = 363600)
  1454  (porque 3! + 6! + 3! + 6! + 0! + 0! = 1454)
   169  (porque 1! + 4! + 5! + 4! = 169)
363601  (porque 1! + 6! + 9! = 363601)
  1454  (porque 3! + 6! + 3! + 6! + 0! + 1! = 1454)
......

La cadena correspondiente a un número n son los términos de la sucesión que empieza en n hasta la primera repetición de un elemento en la sucesión. Por ejemplo, la cadena de 69 es

[69,363600,1454,169,363601,1454]

Consta de una parte no periódica ([69,363600]) y de una periódica ([1454,169,363601]).

Definir las funciones

cadena  :: Integer -> [Integer]
periodo :: Integer -> [Integer]

tales que

  • (cadena n es la cadena correspondiente al número n. Por ejemplo,
cadena 69    ==  [69,363600,1454,169,363601,1454]
cadena 145   ==  [145,145]
cadena 78    ==  [78,45360,871,45361,871]
cadena 569   ==  [569,363720,5775,10320,11,2,2]
cadena 3888  ==  [3888,120966,364324,782,45362,872,45362]
maximum [length (cadena n) | n <- [1..5000]]  ==  61
length (cadena 1479)                          ==  61
  • (periodo n) es la parte periódica de la cadena de n. Por ejemplo,
periodo 69    ==  [169,363601,1454]
periodo 145   ==  [145]
periodo 78    ==  [45361,871]
periodo 569   ==  [2]
periodo 3888  ==  [872,45362]
maximum [length (periodo n) | n <- [1..5000]]  ==  3
length (periodo 1479)                          ==  3

Soluciones

-- Definición de cadena
-- ====================

cadena :: Integer -> [Integer]
cadena n = reverse (extension [n])

extension :: [Integer] -> [Integer]
extension (n:ns)
  | m `elem` (n:ns) = m : n : ns
  | otherwise       = extension (m : n : ns)
  where m = siguiente n

siguiente :: Integer -> Integer
siguiente n =
  sum [factorial d | d <- digitos n]

factorial :: Integer -> Integer
factorial n =
  product [1..n]

digitos :: Integer -> [Integer]
digitos n =
  [read [c] | c <- show n]

-- Definición de periodo
-- =====================

periodo :: Integer -> [Integer]
periodo n =
  reverse (x : takeWhile (/= x) xs)
  where (x:xs) = reverse (cadena n)