diff --git a/day11/src/main.rs b/day11/src/main.rs
index fd87547..9052dd9 100644
--- a/day11/src/main.rs
+++ b/day11/src/main.rs
@@ -1,148 +1,62 @@
-use std::collections::VecDeque;
+use std::collections::HashMap;
 
 fn main() {
     let input = std::fs::read_to_string("input").unwrap();
     let stones = parse(&input);
-    println!("{}", pt1(&stones));
-    println!("{}", pt2(&stones));
+    println!("{}", b4(&stones, 25));
+    println!("{}", b4(&stones, 75));
 }
 
-fn pt1(stones: &[u128]) -> usize {
-    blink2(stones, 25)
-}
-
-fn pt2(stones: &[u128]) -> usize {
-    let mut total = 0;
-    for stone in stones {
-        total += b4(vec![*stone], 75);
+fn b4(stones: &[u64], blinks: usize) -> usize {
+    let mut cache = HashMap::new();
+    for &stone in stones {
+        cache.entry(stone).and_modify(|n| *n += 1).or_insert(1usize);
     }
-    total
-}
-
-fn blink2(stones: &[u128], blinks: usize) -> usize {
-    let mut stones = VecDeque::from_iter(stones.iter().copied());
 
     for _blink in 0..blinks {
-        let mut rots = 0;
-        while rots < stones.len() {
-            let stone = stones[0];
-            let digits = stone.to_string();
-
+        let mut new_cache = HashMap::new();
+        for (stone, count) in cache.into_iter() {
             match stone {
                 0 => {
-                    stones[0] = 1;
-                    stones.rotate_left(1);
-                    rots += 1;
+                    new_cache
+                        .entry(1)
+                        .and_modify(|n| *n += count)
+                        .or_insert(count);
                 }
-                _ if digits.len() % 2 == 0 => {
-                    let mid = digits.len() / 2;
-                    let left = digits[0..mid].parse().unwrap();
-                    let right = digits[mid..].parse().unwrap();
-                    stones[0] = left;
-                    stones.rotate_left(1);
-                    stones.push_front(right);
-                    stones.rotate_left(1);
-                    rots += 2;
+                _ if (stone.ilog10() + 1) % 2 == 0 => {
+                    let (left, right) = split(stone);
+                    new_cache
+                        .entry(left)
+                        .and_modify(|n| *n += count)
+                        .or_insert(count);
+                    new_cache
+                        .entry(right)
+                        .and_modify(|n| *n += count)
+                        .or_insert(count);
                 }
                 _ => {
-                    stones[0] = stone * 2024;
-                    stones.rotate_left(1);
-                    rots += 1;
+                    new_cache
+                        .entry(stone * 2024)
+                        .and_modify(|n| *n += count)
+                        .or_insert(count);
                 }
             }
         }
-        stones.rotate_right(rots);
-    }
-    stones.len()
-}
-
-fn b4(stones: Vec<u128>, blinks: usize) -> usize {
-    let mut total = stones.len();
-    let mut stones = VecDeque::from_iter(stones);
-
-    for blink in 0..blinks {
-        let len = stones.len();
-        if len > 10_000_000 {
-            println!("splitting; started with {blinks} blinks to go, blinked {blink} times");
-            let mid = len / 2;
-            let stones = stones.make_contiguous().to_vec();
-            let iter = &mut stones.into_iter();
-            let left: Vec<_> = iter.take(mid).collect();
-            let right: Vec<_> = iter.collect();
-            // otherwise it gets double-counted at the start of the function in the
-            // recursive call
-            total -= left.len();
-            total -= right.len();
-            let blinks = blinks - blink;
-            total += b4(left, blinks);
-            total += b4(right, blinks);
-            break;
-        } else {
-            let mut rots = 0;
-            while rots < stones.len() {
-                let stone = stones[0];
-                let digits = stone.to_string();
-
-                match stone {
-                    0 => {
-                        stones[0] = 1;
-                        stones.rotate_left(1);
-                        rots += 1;
-                    }
-                    _ if digits.len() % 2 == 0 => {
-                        let mid = digits.len() / 2;
-                        let left = digits[0..mid].parse().unwrap();
-                        let right = digits[mid..].parse().unwrap();
-                        stones[0] = left;
-                        stones.rotate_left(1);
-                        stones.push_front(right);
-                        stones.rotate_left(1);
-                        rots += 2;
-                        total += 1;
-                    }
-                    _ => {
-                        stones[0] = stone * 2024;
-                        stones.rotate_left(1);
-                        rots += 1;
-                    }
-                }
-            }
-            stones.rotate_right(rots);
-        }
-    }
-    total
-}
-
-fn blink3(mut stones: Vec<u128>, blinks: usize) -> usize {
-    let mut total = stones.len();
-    for blink in 0..blinks {
-        let mut rights = Vec::new();
-        for stone in stones.iter_mut() {
-            let digits = stone.to_string();
-            match stone {
-                0 => {
-                    *stone = 1;
-                }
-                _ if digits.len() % 2 == 0 => {
-                    let mid = digits.len() / 2;
-                    let left = digits[0..mid].parse().unwrap();
-                    let right = digits[mid..].parse().unwrap();
-                    *stone = left;
-                    rights.push(right);
-                    total += 1;
-                }
-                _ => {
-                    *stone *= 2024;
-                }
-            }
-        }
-        total += blink3(rights, blinks - blink);
+        cache = new_cache;
     }
 
-    total
+    cache.values().sum()
 }
 
-fn parse(input: &str) -> Vec<u128> {
+fn split(num: u64) -> (u64, u64) {
+    let num_digits = num.ilog10() + 1;
+    let div = num_digits / 2;
+    let left = num.div_euclid(10u64.pow(div));
+    let right = num.rem_euclid(10u64.pow(div));
+    (left, right)
+}
+
+fn parse(input: &str) -> Vec<u64> {
     input
         .trim()
         .split(' ')
@@ -159,10 +73,4 @@ mod test {
         let stones = parse("125 17");
         assert_eq!(55312, pt1(&stones));
     }
-
-    #[test]
-    fn p2() {
-        let stones = parse("125 17");
-        assert_eq!(55312, b4(stones, 25));
-    }
 }