A 7/lex.mll => 7/lex.mll +15 -0
@@ 0,0 1,15 @@
+{
+type token =
+ | Cd of string
+ | File of int * string
+ | Cdup | Ls | Dir of string | Eof
+
+let i = int_of_string
+}
+
+rule token = parse
+ | "$ cd " ([^'\n']+ as d) '\n' { if d = ".." then Cdup else Cd d }
+ | "$ ls\n" { Ls }
+ | "dir " ([^'\n']+ as d) '\n' { Dir d }
+ | (['0'-'9']+ as sz) ' ' ([^'\n']+ as f) '\n' { File (i sz, f) }
+ | eof { Eof }
A 7/t1.ml => 7/t1.ml +56 -0
@@ 0,0 1,56 @@
+open Lex
+
+module StrMap = Map.Make(String)
+
+type thing =
+ | Dir of string
+ | File of int
+
+let joinpath l = List.fold_left (^) "" l
+
+let rec f lexbuf path (map: (thing list) StrMap.t) =
+ match Lex.token lexbuf with
+ | Eof -> map
+ | Cd dir -> f lexbuf (dir :: path) map
+ | Cdup -> f lexbuf (List.tl path) map
+ | Ls -> f lexbuf path map
+ | _ as tok ->
+ let map, update =
+ match tok with
+ | Dir d ->
+ let update e =
+ e |> Option.get |> List.cons (Dir d) |> Option.some
+ in
+ (StrMap.add (joinpath (d :: path)) [] map, update)
+ | File (sz, _) ->
+ let update e =
+ e |> Option.get |> List.cons (File sz) |> Option.some
+ in
+ (map, update)
+ | _ -> failwith "no way"
+ in
+ map |> StrMap.update (joinpath path) update |> f lexbuf path
+
+let mem = ref StrMap.empty
+
+let rec solve e map =
+ match StrMap.find_opt e !mem with
+ | Some v -> v
+ | None ->
+ let rec aux = function
+ | File sz :: l -> sz + aux l
+ | Dir d :: l -> solve (d ^ e) map + aux l
+ | [] -> 0
+ in
+ let res = StrMap.find e map |> aux in
+ mem := StrMap.add e res !mem;
+ res
+
+let sub_sum _ a = (+) (if a <= 100000 then a else 0)
+
+let () =
+ let map = StrMap.singleton "/" [] in
+ f (Lexing.from_channel stdin) [] map |> solve "/" |> ignore;
+ StrMap.fold sub_sum !mem 0
+ |> Printf.printf "%d\n"
+
A 7/t2.ml => 7/t2.ml +58 -0
@@ 0,0 1,58 @@
+open Lex
+
+module StrMap = Map.Make(String)
+
+type thing =
+ | Dir of string
+ | File of int
+
+let joinpath l = List.fold_left (^) "" l
+
+let rec f lexbuf path (map: (thing list) StrMap.t) =
+ match Lex.token lexbuf with
+ | Eof -> map
+ | Cd dir -> f lexbuf (dir :: path) map
+ | Cdup -> f lexbuf (List.tl path) map
+ | Ls -> f lexbuf path map
+ | _ as tok ->
+ let map, update =
+ match tok with
+ | Dir d ->
+ let update e =
+ e |> Option.get |> List.cons (Dir d) |> Option.some
+ in
+ (StrMap.add (joinpath (d :: path)) [] map, update)
+ | File (sz, _) ->
+ let update e =
+ e |> Option.get |> List.cons (File sz) |> Option.some
+ in
+ (map, update)
+ | _ -> failwith "no way"
+ in
+ map |> StrMap.update (joinpath path) update |> f lexbuf path
+
+let mem = ref StrMap.empty
+
+let rec solve e map =
+ match StrMap.find_opt e !mem with
+ | Some v -> v
+ | None ->
+ let rec aux = function
+ | File sz :: l -> sz + aux l
+ | Dir d :: l -> solve (d ^ e) map + aux l
+ | [] -> 0
+ in
+ let res = StrMap.find e map |> aux in
+ mem := StrMap.add e res !mem;
+ res
+
+let find_optimal total _ cand curr =
+ if cand < curr && total - cand < 70_000_000 - 30_000_000 then cand
+ else curr
+
+let () =
+ let map = StrMap.singleton "/" [] in
+ let total = f (Lexing.from_channel stdin) [] map |> solve "/" in
+ StrMap.fold (find_optimal total) !mem 70_000_000
+ |> Printf.printf "%d\n"
+