import Data.Char (digitToInt)
import qualified Data.Map as Map

digitFactorial :: Integer -> Integer
digitFactorial n = case n of 
    0 -> 1
    1 -> 1
    2 -> 2
    3 -> 6
    4 -> 24
    5 -> 120
    6 -> 720
    7 -> 5040
    8 -> 40320
    9 -> 362880

type ChainMap = Map.Map Integer Integer
initialMap :: ChainMap
initialMap = Map.fromList [(169, 3), (363601, 3), (1454, 3),
                           (871, 2), (872, 2), (45361, 2), (45362, 2),
                           (1, 1), (2, 1), (145, 1), (40585, 1)]

sumOfFactorialOfDigits :: Integer -> Integer
sumOfFactorialOfDigits n = sum $ map (digitFactorial . fromIntegral . digitToInt) $ show n

getChainLength :: Integer -> ChainMap -> (Integer, ChainMap)
getChainLength n chainMap = case Map.lookup n chainMap of 
    Just length -> (length, chainMap)
    Nothing     -> let next = sumOfFactorialOfDigits n
                       (nextLength, nextChainMap) = getChainLength next chainMap
                       length = nextLength + 1
                   in (length, Map.insert n length nextChainMap)

numOfLoops :: Integer -> Integer -> (Integer, ChainMap)
numOfLoops bound length = foldr (\n (num, oldMap) -> let (chainLength, newMap) = getChainLength n oldMap
                                                     in (num + if chainLength == length then 1 else 0, newMap)) (0, initialMap) [3..bound]

main = print $ let (length, sizeMap) = numOfLoops 1000000 60
               in length
