Advent of Code 2025 is back, this time with only 12 puzzles, but as always they’re fun to do. We’re at Day 3, but I’m mostly impressed by Day 2, it has something special, and shows the genius behind the puzzle-making ❤️
Please make sure you take a look at it before reading further. Here’s a generated image to make sure you do not accidentally read the solution down below.

Part 1
In Part 1, you have to compute the sum of “invalid” identifiers. An invalid identifier is any number formed by repeating a sequence of digits twice:
99has9repeated twice1212has12repeated twice too- and so is
38593859which has3859repeated twice
The input is an inclusive start-end range, and for each range you’ll have to find all invalid
identifiers and sum them. For example 75-120 should return the sum 77 + 88 + 99.
This looks like a simple sum:
(start..=end).filter(is_invalid_id).sum();
Let’s look closer at is_invalid_id, we can already see that it must respect two conditions:
- Has an even number of characters
- First half == Second half
You can play with this solution on the playground. And it looks something like:
fn compute_sum(start: &str, end: &str) -> u64 {
let start = start.parse::<u64>().unwrap();
let end = end.parse::<u64>().unwrap();
(start..end).filter(is_invalid_id).sum()
}
fn is_invalid_id(v: &u64) -> bool {
let representation = v.to_string();
// for odd length the two halfs wont have same size, which is fine
let middle = representation.len() / 2;
let (first, second) = representation.split_at(middle);
first == second
}
This will run fast for the part 1 problem
Part 1: 3xxxxxxxxx3 (41.8ms)
Now what if I told you we could go down by a few orders of magnitude?
Part 1: 3xxxxxxxxx3 (3.4µs)
Yup, that’s more than 12_000x speedup.
Numbers, numbers everywhere
Let’s look again at our problem and take some examples:
99>91212>12123123>12338593859>3859
You might say, hey @moze, we know we’ve seen this before. And I might say, sure, but look closely, look at that beautiful number! Let’s decompose these numbers. Notice a pattern?
99 = 9 + 9 * 101212 = 12 + 12 * 100123123 = 123 + 123 * 100038593859 = 3859 + 3859 * 1000
Yup, any invalid number
Knowing that we can mathematically compute the sum of the
Where does our sum start and end? This depends on what I’ll be calling a bin. Each bin is a range of 75-1300, the first bin is 7-9 and the last bin is 10-12. Hence,
our formula becomes:
The sum of numbers from
where
fn main() {
assert_eq!(compute_sum(7, 9, 1), 77 + 88 + 99);
assert_eq!(compute_sum(10, 12, 2), 1010 + 1111 + 1212);
}
fn compute_sum(s: u64, e: u64, len: u32) -> u64 {
let count = e - s + 1;
let sum_base = count * (s + e) / 2;
let multiplier = 10u64.pow(len) + 1;
sum_base * multiplier
}
Now I leave it to you to find a simple way to find all the bins for a given range. As a hint, you can use this simple
technique to find the start and end of a bin without checking for min and max, i.e. for the first bin you’ll get 1..9
rather than 7..9:
for len in 1..=4u32 {
let min_seed = 10u64.pow(len - 1);
let max_seed = 10u64.pow(len) - 1;
println!("min = {min_seed}, max = {max_seed}");
}
Part 2
So you thought that we were done? Nah, the puzzle gets nicer, and you’ll have to throw most of what you’ve done in the first one :)
Now the invalid identifiers are not just a number repeated twice, but any number containing repeating blocks of digits.
99is9twice123123is123two times121212is12three times111111is1six times- etc.
We see that the same ideas as we had before apply here, notice that 121212 can be written as
12 + 12*10^2 + 12*10^4. That 123123 can be written 123 + 123*10^3, and 111111 can be written
1 + 1*10^1 + 1*10^2 + ... + 1*10^5.
Notice anything here? Each term is multiplied by a power of 10. That’s a geometric series, and there’s a closed-form formula for that. I will let you enjoy the rest of the puzzle 😄
TIP
Look at those divisors 😉