Ir al contenido principal

Entero positivo con ciertas propiedades

El 6 de octubre, se propuso en el blog Gaussianos el siguiente problema

Demostrar que para todo entero positivo n, existe otro entero positivo que tiene las siguientes propiedades:

  1. Tiene exactamente n dígitos.
  2. Ninguno de sus dígitos es 0.
  3. Es divisible por la suma de sus dígitos.

Definir la función

especiales :: Integer -> [Integer]

tal que (especiales n) es la lista de los números enteros que cumplen las 3 propiedades anteriores para n. Por ejemplo,

take 3 (especiales 2)  ==  [12,18,21]
take 3 (especiales 3)  ==  [111,112,114]
head (especiales 30)   ==  111111111111111111111111111125
length (especiales 3)  ==  108
null (especiales 1000) ==  False

En el primer ejemplo, 12 es un número especial para 2 ya que tiene exactamente 2 dígitos, ninguno de sus dígitos es 0 y 12 es divisible por la suma de sus dígitos.


Soluciones

-- 1ª definición
-- =============

especiales :: Integer -> [Integer]
especiales n = [x | x <- [(10^n-1) `div` 9..10^n-1]
                  , esEspecial x]

esEspecial :: Integer -> Bool
esEspecial x =
    0 `notElem` digitos &&
    x `mod` sum digitos == 0
    where digitos = [read [d] | d <- show x]

-- 2ª definición
-- =============

especiales2 :: Integer -> [Integer]
especiales2 n = [ m | (m, s) <- generador n
                    , m `mod` s == 0]

-- (generador n) es la lista de los pares formados por los números con n
-- dígitos distintos de 0 junto son la suma de sus dígitos. Por ejemplo,
--    λ> generador 2
--    [(11,2), (12,3), (13,4), (14,5), (15,6), (16,7), (17,8), (18,9), (19,10),
--     (21,3), (22,4), (23,5), (24,6), (25,7), (26,8), (27,9), (28,10),(29,11),
--     (31,4), (32,5), (33,6), (34,7), (35,8), (36,9), (37,10),(38,11),(39,12),
--     (41,5), (42,6), (43,7), (44,8), (45,9), (46,10),(47,11),(48,12),(49,13),
--     (51,6), (52,7), (53,8), (54,9), (55,10),(56,11),(57,12),(58,13),(59,14),
--     (61,7), (62,8), (63,9), (64,10),(65,11),(66,12),(67,13),(68,14),(69,15),
--     (71,8), (72,9), (73,10),(74,11),(75,12),(76,13),(77,14),(78,15),(79,16),
--     (81,9), (82,10),(83,11),(84,12),(85,13),(86,14),(87,15),(88,16),(89,17),
--     (91,10),(92,11),(93,12),(94,13),(95,14),(96,15),(97,16),(98,17),(99,18)]
generador :: Integer -> [(Integer, Integer)]
generador 0 = [(0,0)]
generador n = [(m*10+c, s+c) | (m,s) <- generador (n-1)
                             , c <- [1..9] ]

-- Eficiencia
-- ==========

--    λ> :set +s
--    λ> null (especiales 2000)
--    False
--    (28.02 secs, 11726529808 bytes)
--    λ> null (especialesA7 2000)
--    False
--    (0.04 secs, 6036972 bytes)