Números divisibles respecto de una sucesión
El enunciado de un problema para la IMO (Olimpiada Internacional de Matemáticas) de 1968 es
Sean a(0), a(1), …, a(n) (con n ≥ 1) números enteros positivos. Encontrar todos los números enteros y tales que
a(0) | y; (a(0)+a(1)) | (y+a(1)); … ; (a(0)+a(n)) | (y+a(n)).
donde «x | y» significa que «y es divisible por x».
Se dice que un número y es divisible respecto de la sucesión a(0), a(1), …, a(n) si verifica la propiedad anterior; es decir,
| 
					 1  | 
						      a(0) | y; (a(0)+a(1)) | (y+a(1)); ... ; (a(0)+a(n)) | (y+a(n)).  | 
					
Definir la función
| 
					 1  | 
						   divisiblesSucesion :: [Integer] -> [Integer]  | 
					
tal que (divisiblesSucesion xs) es la lista de los números enteros divisibles respecto de xs. Por ejemplo,
| 
					 1 2 3 4  | 
						   take 6 (divisiblesSucesion [2,5,3])     ==  [2,72,142,212,282,352]    divisiblesSucesion [3,5..30] !! (10^5)  ==  144144000003    divisiblesSucesion [3,5..30] !! (10^6)  ==  1441440000003    divisiblesSucesion [3,5..30] !! (10^7)  ==  14414400000003  | 
					
Soluciones
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73  | 
						import Test.QuickCheck (quickCheck) -- 1ª solución -- =========== divisiblesSucesion :: [Integer] -> [Integer] divisiblesSucesion xs =   filter (esDivisibleSucesion xs) [1..] -- (esDivisibleSucesion xs y) se verifica si y es divisible respecto de -- la sucesión xs. Por ejemplo, --    esDivisibleSucesion [2,5,3] 72  ==  True --    esDivisibleSucesion [2,5,3] 12  ==  False esDivisibleSucesion :: [Integer] -> Integer -> Bool esDivisibleSucesion [] _      = True esDivisibleSucesion (a0:as) y =   y `mod` a0 == 0 &&   and [(y+a) `mod` (a0+a) == 0 | a <- as] -- 2ª solución -- =========== -- En los siguientes cálculos --    λ> take 5 (divisiblesSucesion [2,3,5]) --    [2,72,142,212,282] --    λ> foldl1 lcm [2, 2+3, 2+5] --    70 --    λ> take 5 (divisiblesSucesion [2,3,5,6]) --    [2,282,562,842,1122] --    λ> foldl1 lcm [2, 2+3, 2+5, 2+6] --    280 --    λ> take 5 (divisiblesSucesion [1,3,5,6]) --    [1,85,169,253,337] --    λ> foldl1 lcm [1, 1+3, 1+5, 1+6] --    84 -- se observa que los resultados son progresiones aritméticas cuyo -- primer elemento es a(0) y la diferencia es el mínimo común múltiplo -- de [a(0), a(0)+a(1), a(0)+a(2), ..., a(0)+a(n)] divisiblesSucesion2 :: [Integer] -> [Integer] divisiblesSucesion2 []      = [1..] divisiblesSucesion2 (a0:as) = [a0,a0+m..]   where m = mcm (a0 : [a0+a | a <- as]) -- (mcm xs) es el mínimo común múltiplo de xs. Por ejemplo, --    mcm [2,5,3]  ==  30 --    mcm [2,2+5,2+3]  ==  70 mcm :: [Integer] -> Integer mcm = foldl1 lcm -- Comprobación de equivalencia -- ============================ -- La propiedad es prop_equivalencia :: [Integer] -> Bool prop_equivalencia  xs =   take 3 (divisiblesSucesion ys) == take 3 (divisiblesSucesion2 ys)   where ys = take 5 [1 + (x `mod` 10) | x <- xs] -- La comprobación es --    λ> quickCheck prop_equivalencia --    +++ OK, passed 100 tests. -- Comparación de eficiencia -- ========================= -- La comparación es --    λ> divisiblesSucesion [3,5..30] !! 20 --    28828803 --    (16.86 secs, 15,933,990,784 bytes) --    λ> divisiblesSucesion2 [3,5..30] !! 20 --    28828803 --    (0.01 secs, 112,496 bytes)  | 
					
Nuevas soluciones
- En los comentarios se pueden escribir nuevas soluciones.
 - El código se debe escribir entre una línea con <pre lang="haskell"> y otra con </pre>