2025 Advent of Code Summary
Note: the number of problems has been changed from 25 to 12 this year.
Day -Part 1- -Part 2-
12 00:15:03 00:15:05
11 00:03:23 00:09:48
10 00:05:16 00:25:38
9 00:01:32 00:33:22
8 00:04:11 00:08:59
7 00:09:25 00:13:45
6 00:04:06 00:07:46
5 00:03:50 00:06:40
4 00:04:18 00:08:48
3 00:03:38 00:09:51
2 00:05:01 00:23:55
1 00:02:54 00:12:32
Day 12
-
Enumerate all unique rotations/reflections of each shape and represent each possible placement as a bitmask of occupied cells. Search for a non-overlapping selection of placements matching the required counts.
-
Happy holiday :)
Day 11
-
Counts graph by running memoized DFS on the directed graph where each node’s value is the sum of its successors’ values, with
out as the base case of 1.
-
Same, but arguments the state with a bitmask tracking whether
dac and fft have been visited so that only paths whose mask has both bit set contribute at out.
Day 10
-
BFS on bitmask states where the start is all-off, each button is an XOR toggle mask, and the minimal number of process is the shortest path distance from start to target, summed over all machines.
-
Choose nonnegative integers \(x_k\) (button press counts) so that for each counter \(j\), \(\sum_{k: j\in \text{button } k} x_k = t_j\), then minimize \(\sum_k x_k\) rather than exploring raw counter states. A BFS over counter configurations blows up because the state space grows something like \(\prod_j(t_j+1)\) (I think, unproven), so it’s far more scalable to hand this ILP to a solver like
z3 and let it find the minimal solution.
Day 9
-
Brute-force.
-
Okay, now we are talking.. Draw the red-loop polygon and flood-fill from the outside to mark disallowed tiles, then check every pair of red corners and keep only those rectangles whose entire area (via a prefix-sum check) lies within the remaining allowed region. My approach and implementation with C++ took around six minute to complete.
Day 8
-
Kruskal-style unions on all edges order by distance, but stop after the 1000 shortest edges.
-
Keep going past 1000 edges until everything is connected.
Day 7
-
Brute-force. For some reason, I thought it asks to count how many
| at the end…
-
DP. Define
f(r, c) that returns the number of timelines from cell (r, c) downward (splitting on ^), and memorize it so each cell’s count is computed once and reused.
fn dp(r, c):
if r == last_row:
return 1
if grid[r+1][c] == '^': // splitter below
return dp(r + 1, c - 1) + dp(r + 1, c + 1)
else: // straight down
return dp(r + 1, c)
Day 6
-
Split by space, then simulation.
-
Split it into vertical problem block at all-space columns, then for each block read digits top-to-bottom in each column (right to left) to form numbers.
g = [list(r.ljust(w)) for r in rows]
sep = [all(g[r][c] == ' ' for r in range(h)) for c in range(w)]
Day 4
-
Simulation.
-
Simulation, but multiple rounds.
Day 3
-
Brute-force.
-
Treat each row as: “remove some digits so the remaining 12 are as big as possible from left to right”. Hint: use monotonic stack.
Day 2
-
Brute-force. For each range
(l, r), check all integers from 1 up to half the number of digits in r, inclusive.
-
Similar idea, but remember to handle duplicates. For example,
1111 can be represented as 1 repeated four times or 11 repeated two times.
Day 1
-
Modular arithmetic.
-
Brute-force.
Last edited: Dec 10, 2025