|
| 1 | +import qualified Data.Map.Strict as Map |
| 2 | +import Data.List (sort, group) |
| 3 | +import Control.Arrow ((&&&)) |
| 4 | + |
| 5 | +type Template = Map.Map String Char |
| 6 | +type FreqMap = Map.Map String Int |
| 7 | +type CountMap = Map.Map Char Int |
| 8 | + |
| 9 | +parseInput :: String -> (String, Template) |
| 10 | +parseInput l = (start, Map.fromList $ map f patterns) |
| 11 | + where (start:_:patterns) = lines l |
| 12 | + f p = let [l, _, r] = words p in (l, head r) |
| 13 | + |
| 14 | +freqMap :: String -> Template -> FreqMap |
| 15 | +freqMap [_] m = Map.empty |
| 16 | +freqMap (l:s@(r:_)) m = add [l, r] 1 $ freqMap s m |
| 17 | + |
| 18 | +step :: [(String, Int)] -> Template -> FreqMap -> CountMap -> (FreqMap, CountMap) |
| 19 | +step [] templ freq count = (freq, count) |
| 20 | +step ((p@[l,r],i):ss) templ freq count = step ss templ freq' count' |
| 21 | + where x = templ Map.! p |
| 22 | + p'l = [l, x] |
| 23 | + p'r = [x, r] |
| 24 | + freq' = add p'r i $ add p'l i $ sub p i freq |
| 25 | + count' = add x i count |
| 26 | + |
| 27 | +get k = maybe 0 id . Map.lookup k |
| 28 | +add k n m = Map.insert k (get k m + n) m |
| 29 | +sub k n m = Map.insert k (get k m - n) m |
| 30 | + |
| 31 | +main = parseInput <$> readFile "input.txt" |
| 32 | + >>= \i -> mapM_ print [f 10 i, f 40 i] |
| 33 | + where |
| 34 | + f n (s, templ) = diff $ snd $ foldl (const . g) (freq, count) [1..n] |
| 35 | + where |
| 36 | + freq = freqMap s templ |
| 37 | + count = Map.fromList $ map (head &&& length) $ group $ sort s |
| 38 | + g (s, x) = step (Map.toList s) templ s x |
| 39 | + diff m = maximum l - minimum l |
| 40 | + where l = Map.elems m |
0 commit comments