1use crate::util::iter::*;
3use crate::util::parse::*;
4
5type Range = [u32; 2];
6type Pair = [u64; 2];
7
8const FIRST: [Range; 5] = [[2, 1], [4, 2], [6, 3], [8, 4], [10, 5]];
9const SECOND: [Range; 6] = [[3, 1], [5, 1], [6, 2], [7, 1], [9, 3], [10, 2]];
10const THIRD: [Range; 2] = [[6, 1], [10, 1]];
11
12pub fn parse(input: &str) -> Vec<Pair> {
13 input.iter_unsigned::<u64>().chunk::<2>().collect()
14}
15
16pub fn part1(input: &[Pair]) -> u64 {
17 sum(&FIRST, input)
18}
19
20pub fn part2(input: &[Pair]) -> u64 {
21 sum(&FIRST, input) + sum(&SECOND, input) - sum(&THIRD, input)
22}
23
24fn sum(ranges: &[Range], input: &[Pair]) -> u64 {
25 let mut result = 0;
26
27 for &[digits, size] in ranges {
28 let digits_power = 10_u64.pow(digits);
29 let size_power = 10_u64.pow(size);
30
31 let step = (digits_power - 1) / (size_power - 1);
32 let start = step * (size_power / 10);
33 let end = step * (size_power - 1);
34
35 for &[from, to] in input {
36 let lower = from.next_multiple_of(step).max(start);
37 let upper = to.min(end);
38
39 if lower <= upper {
40 let n = (upper - lower) / step;
41 let triangular = n * (n + 1) / 2;
42 result += lower * (n + 1) + step * triangular;
43 }
44 }
45 }
46
47 result
48}