190 lines
4.7 KiB
C
190 lines
4.7 KiB
C
|
|
#include <stdint.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
#include <omp.h>
|
||
|
|
|
||
|
|
#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;
|
||
|
|
}
|