153 lines
3.2 KiB
C++
153 lines
3.2 KiB
C++
|
#include <fstream>
|
||
|
#include <iostream>
|
||
|
#include <sstream>
|
||
|
#include <string>
|
||
|
#include <unordered_map>
|
||
|
#include "hash.h"
|
||
|
|
||
|
using namespace std;
|
||
|
|
||
|
struct Node {
|
||
|
unsigned long long value;
|
||
|
Node *next;
|
||
|
};
|
||
|
|
||
|
Node *parseList(const char *path) {
|
||
|
ifstream input(path);
|
||
|
string line;
|
||
|
|
||
|
getline(input, line);
|
||
|
stringstream ss;
|
||
|
ss << line;
|
||
|
unsigned long long a;
|
||
|
|
||
|
// head
|
||
|
ss >> a;
|
||
|
Node *curr = new Node();
|
||
|
curr->value = a;
|
||
|
Node *head = curr;
|
||
|
|
||
|
// rest
|
||
|
while (ss >> a) {
|
||
|
Node *prev = curr;
|
||
|
curr = new Node();
|
||
|
curr->value = a;
|
||
|
prev->next = curr;
|
||
|
}
|
||
|
|
||
|
return head;
|
||
|
}
|
||
|
|
||
|
void blink(Node *head) {
|
||
|
Node *curr = head;
|
||
|
while (curr != nullptr) {
|
||
|
// get next already, to skip newly appended elements
|
||
|
Node *next = curr->next;
|
||
|
|
||
|
// do blink
|
||
|
string num = to_string(curr->value);
|
||
|
if (curr->value == 0) {
|
||
|
curr->value = 1;
|
||
|
} else if (num.size() % 2 == 0) {
|
||
|
string num1 = num.substr(0, num.size() / 2);
|
||
|
string num2 = num.substr(num.size() / 2, num.size() / 2);
|
||
|
|
||
|
Node *new_node = new Node();
|
||
|
curr->value = stol(num1);
|
||
|
curr->next = new_node;
|
||
|
new_node->value = stol(num2);
|
||
|
new_node->next = next;
|
||
|
} else {
|
||
|
curr->value = curr->value * 2024;
|
||
|
}
|
||
|
curr = next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int length(Node *head) {
|
||
|
int ret = 0;
|
||
|
Node *curr = head;
|
||
|
while (curr != nullptr) {
|
||
|
ret++;
|
||
|
curr = curr->next;
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void printList(Node *head) {
|
||
|
Node *curr = head;
|
||
|
|
||
|
while (curr != nullptr) {
|
||
|
cout << curr->value << " ";
|
||
|
curr = curr->next;
|
||
|
}
|
||
|
cout << endl;
|
||
|
}
|
||
|
|
||
|
// highly inefficient
|
||
|
int part1(const char *path) {
|
||
|
Node *head = parseList(path);
|
||
|
for (int i = 0; i < 25; i++) {
|
||
|
blink(head);
|
||
|
}
|
||
|
|
||
|
return length(head);
|
||
|
}
|
||
|
|
||
|
unordered_map<tuple<long, int>, long> memo;
|
||
|
|
||
|
unsigned long long doBlinks(unsigned long long value, int iterations) {
|
||
|
if (iterations == 0) {
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// cache hit
|
||
|
if (memo.count(make_tuple(value, iterations))) {
|
||
|
// return memo.at(make_tuple(value, iterations));
|
||
|
return memo[make_tuple(value, iterations)];
|
||
|
}
|
||
|
|
||
|
// cache miss -> do blink
|
||
|
if (value == 0) {
|
||
|
long ret = doBlinks(1 , iterations - 1);
|
||
|
memo[make_tuple(value, iterations)] = ret;
|
||
|
// memo.insert(make_pair(make_tuple(value, iterations), ret));
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
unsigned long long ret = 0;
|
||
|
string num = to_string(value);
|
||
|
if (num.size() % 2 == 0) {
|
||
|
string num1 = num.substr(0, num.size() / 2);
|
||
|
string num2 = num.substr(num.size() / 2, num.size() / 2);
|
||
|
ret += doBlinks(stol(num1), iterations - 1);
|
||
|
ret += doBlinks(stol(num2), iterations - 1);
|
||
|
memo[make_tuple(value, iterations)] = ret;
|
||
|
return ret;
|
||
|
} else {
|
||
|
long ret = doBlinks(value * 2024, iterations - 1);
|
||
|
memo[make_tuple(value, iterations)] = ret;
|
||
|
return ret;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
unsigned long long part2(const char *path) {
|
||
|
Node *head = parseList(path);
|
||
|
|
||
|
unsigned long long sum = 0;
|
||
|
|
||
|
while (head != nullptr) {
|
||
|
sum += doBlinks(head->value, 75);
|
||
|
head = head->next;
|
||
|
}
|
||
|
|
||
|
return sum;
|
||
|
}
|
||
|
|
||
|
int main(int argc, char *argv[]) {
|
||
|
cout << "example1: " << part1("example") << endl;
|
||
|
cout << "input1: " << part1("input") << endl;
|
||
|
cout << "example2: " << part2("example") << endl;
|
||
|
cout << "input2: " << part2("input") << endl;
|
||
|
return 0;;
|
||
|
}
|