-
Notifications
You must be signed in to change notification settings - Fork 0
/
run.hs
62 lines (54 loc) · 1.62 KB
/
run.hs
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
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TypeApplications #-}
import AoC
import AoC.Grid
import Data.List
parseAll :: String -> [Int]
parseAll input = read @[Int] $ "[" ++ input ++ "]"
align :: (Int -> Int -> Int) -> [Int] -> [Int] -> Int
align cost range xs =
minimum
. map (alignTo cost xs)
$ range
alignTo :: (Int -> Int -> Int) -> [Int] -> Int -> Int
alignTo cost xs i = sum $ map (cost i) xs
-- part1 corresponds to finding the minimum of
-- f(x) = sum_y | y - x |
-- this is known to happen at x = median Y
part1 :: [Int] -> Int
part1 xs =
let xs' = map fromIntegral xs
m = median xs'
range = [floor m..ceiling m]
cost i x = abs (x - i)
in align cost range xs
-- part2 corresponds to finding the minimum of
-- f(x) = sum_y |y-x|(|y-x|+1)/2
-- = sum_y (y-x)²/2 + sum_y |y-x|/2
-- = 1/2 * (sum_y (y-x)² + sum_y |y-x|)
--
-- sum_y (y-x)² has its minimum at x = mean Y
-- sum_y |y-x| has its minimum at x = median Y
--
-- let a = min(mean Y, median Y)
-- b = max(mean Y, median Y)
--
-- both sums grow monotonically outside of the interval [a, b] which
-- implies that the convex function f has its global minimum in that
-- interval.
part2 :: [Int] -> Int
part2 xs =
let xs' = map fromIntegral xs
m1 = median xs'
m2 = mean xs'
[low, high] = sort [m1, m2]
range = [floor low..ceiling high]
cost i x = let d = abs (x - i) in d * (d + 1) `div` 2
in align cost range xs
main = main' "input.txt"
exampleMain = main' "example.txt"
main' file = do
input <- parseAll <$> readFile file
print (part1 input)
print (part2 input)