#include #include #include #include #include #define CHARS_MAX 64 #define MAX_BUYERS 8*1024 #define GENERATION 2000 typedef struct node { struct node *children[19]; uint64_t value; char key; uint8_t is_leaf; } node_t; node_t* create_node() { node_t *node = calloc(1, sizeof(node[0])); return node; } node_t* search(node_t* root, int8_t* word, int len) { node_t* node = root; for (int i = 0; i < len; i++) { if (node->children[word[i] + 9] == NULL) { return NULL; } node = node->children[word[i] + 9]; } return node; } void insert(node_t* root, int8_t* word, int len, uint64_t value) { node_t* node = root; for (int i = 0; i < len; i++) { if (node->children[word[i] + 9] == NULL) { node->children[word[i] + 9] = create_node(); } node = node->children[word[i] + 9]; } node->value = value; node->is_leaf = 1; } void free_node(node_t* node) { for (int i = 0; i < 19; i++) { if (node->children[i] != NULL) { free_node(node->children[i]); } } free(node); } uint64_t generate_new_secret(uint64_t); uint64_t mix(uint64_t, uint64_t); uint64_t prune(uint64_t); int main() { char *p, *buf, c; buf = calloc(CHARS_MAX, sizeof(char)); p = buf; uint64_t *secrets = calloc(MAX_BUYERS, sizeof(secrets[0])); int secret_count = 0; while ((c = getchar()) != EOF) { *p++ = c; if (c != '\n') { continue; } sscanf(buf, "%lu", &secrets[secret_count++]); memset(buf, 0, CHARS_MAX); p = buf; } free(buf); uint64_t sum = 0; uint64_t **prices = calloc(secret_count, sizeof(prices[0])); for (int i = 0; i < secret_count; i++) { prices[i] = calloc(GENERATION + 1, sizeof(prices[0][0])); prices[i][0] = secrets[i] % 10; for (int j = 0; j < GENERATION; j++) { secrets[i] = generate_new_secret(secrets[i]); prices[i][j+1] = secrets[i] % 10; } sum += secrets[i]; } printf("%lu\n", sum); free(secrets); // Calculate diffs int8_t **diffs = calloc(secret_count, sizeof(diffs[0])); for (int i = 0; i < secret_count; i++) { diffs[i] = calloc(GENERATION, sizeof(diffs[0][0])); for (int j = 0; j < GENERATION; j++) { diffs[i][j] = (int8_t)prices[i][j+1] - (int8_t)prices[i][j]; } } int8_t (**sequences)[4] = calloc(secret_count, sizeof(int8_t(*)[4])); for (int i = 0; i < secret_count; i++) { sequences[i] = calloc(GENERATION - 4, sizeof(int8_t[4])); for (int j = 0; j < GENERATION-4; j++) { sequences[i][j][0] = diffs[i][j]; sequences[i][j][1] = diffs[i][j+1]; sequences[i][j][2] = diffs[i][j+2]; sequences[i][j][3] = diffs[i][j+3]; } free(diffs[i]); } free(diffs); node_t *root = calloc(1, sizeof(node_t)); uint64_t max_bananas = 0; for (int i = 0; i < secret_count; i++) { for (int j = 0; j < GENERATION - 4; j++) { int8_t pattern[4]; memcpy(pattern, sequences[i][j], sizeof(sequences[0][0])); node_t *node = search(root, pattern, 4); if (node != NULL && node->is_leaf) { continue; } // Count bananas uint64_t bananas = 0; #pragma omp parallel for for (int k = 0; k < secret_count; k++) { for (int l = 0; l < GENERATION - 4; l++) { if (memcmp(pattern, sequences[k][l], sizeof(sequences[0][0]))) { continue; } #pragma omp critical { bananas += prices[k][l+4]; } break; } } insert(root, pattern, 4, bananas); if (bananas > max_bananas) { max_bananas = bananas; } } } printf("%lu\n", max_bananas); for (int i = 0; i < secret_count; i++) { free(prices[i]); free(sequences[i]); } free_node(root); free(prices); free(sequences); } uint64_t generate_new_secret(uint64_t secret) { uint64_t new_secret = secret; // 1 new_secret = prune(mix(new_secret, new_secret * 64)); // 2 new_secret = prune(mix(new_secret, new_secret / 32)); // 3 new_secret = prune(mix(new_secret, new_secret * 2048)); return new_secret; } uint64_t mix(uint64_t secret, uint64_t value) { return secret ^ value; } uint64_t prune(uint64_t secret) { return secret % 16777216; }