aboutsummaryrefslogtreecommitdiffstats
path: root/src/22/part2.c
blob: ff5d51d36bf051f810a2ee554100f58ff038afe1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include "allocator.h"
#include "aoc.h"
#include "dvec_s.h"
#include "util.h"

#include <assert.h>
#include <stddef.h>
#include <stdlib.h>

size_t
imul(size_t a, size_t b, size_t n)
{
	size_t i, out;

	out = 0;
	for (i = 0; i < sizeof(size_t) * 8; i++, b <<= 1) {
		out = (2 * out) % n;
		if (b & (1ULL << 63))
			out = (out + a) % n;
	}

	return out;
}

size_t
ipow(size_t a, size_t b, size_t n)
{
	size_t i, out;

	out = 1;
	for (i = 0; i < sizeof(size_t) * 8; i++, b <<= 1) {
		out = imul(out, out, n);
		if (b & (1ULL << 63))
			out = imul(out, a, n);
	}

	return out;
}

size_t
modinv(size_t a, size_t n)
{
	return ipow(a, n - 2, n);
}

void
part2(void)
{
	char line[256];
	const char *lpos, *lend;
	size_t answer;
	size_t count;
	size_t times;
	size_t target;
	ssize_t sval;
	size_t mul, off;
	size_t _mul, _off;
	size_t val;

	times = 101741582076661;
	count = 119315717514047;
	target = 2020;

	/* reduce operations to a single multiplication and
	 * addition under modulus 'count' */
	mul = 1;
	off = 0;
	lpos = aoc.input;
	lend = lpos + aoc.input_size;
	while (readtok(line, sizeof(line), '\n', &lpos, lend)) {
		if (sscanf(line, "deal with increment %lu", &val) == 1) {
			/* multiplication : pos = val * pos */
			_mul = val;
			_off = 0;
		} else if (sscanf(line, "cut %li", &sval) == 1) {
			/* addition : pos = pos + val */
			_mul = 1;
			_off = ((size_t) ((ssize_t) count - sval)) % count;
		} else if (!strcmp(line, "deal into new stack")) {
			/* invert : pos = - pos + n - 1 */
			_mul = count - 1;
			_off = count - 1;
		} else if (strspn(line, " \n\r\t\v") == strlen(line)) {
			continue;
		} else {
			assert(false);
		}
		mul = imul(mul, _mul, count);
		off = (imul(off, _mul, count) + _off) % count;
	}

	/* apply multiplication and addition 'times' times.. */
	val = (ipow(mul, times, count) + count - 1) % count;
	val = imul(val, modinv(mul + count - 1, count), count);
	off = imul(off, val, count); /* b' = b * ((a^n - 1) / (a - 1)) */
	mul = ipow(mul, times, count); /* a' = a^n */

	answer = imul((target + count - off) % count, modinv(mul, count), count);
	aoc.answer = aprintf("%lu", answer);
	aoc.solution = "73394009116480";
}