Created
December 14, 2020 22:50
-
-
Save orendon/4c6797185fd8c7978f699146491d2246 to your computer and use it in GitHub Desktop.
Advent of Code - Day 13 Shuttle Search
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <fstream> | |
#include <sstream> | |
#include <string> | |
#include <vector> | |
#include "tmpl.h" | |
using namespace std; | |
int bs_part1(int, int); | |
ll mod_mult_inverse(ll, ll); | |
ll chinese_remainder(vi &, vi &); | |
int main() { | |
// read inputs | |
ifstream fin("inputs/13.txt"); | |
vi busses; | |
vi times; | |
int earliest, time=0; | |
string line, bus_id; | |
fin >> earliest >> line; | |
istringstream comma(line); | |
while(getline(comma, bus_id, ',')) { | |
if (bus_id != "x") { | |
busses.pb(stoi(bus_id)); | |
times.pb(time); | |
} | |
time ++; | |
} | |
// part 1 | |
int p1_min=1e9, bid, dep_time; | |
fore(bus, busses) { | |
dep_time = bs_part1(bus, earliest); | |
if (bus*dep_time < p1_min){ | |
p1_min = bus*dep_time; | |
bid = bus; | |
} | |
} | |
cout << "Part 1: " << bid*(p1_min-earliest) << endl; | |
// part 2 | |
vi remainders; | |
forn(i, 0, busses.size()) remainders.pb(busses[i]-times[i]); | |
remainders[0] = 0; | |
cout << "Part 2: " << chinese_remainder(busses, remainders) << endl; | |
return 0; | |
} | |
int bs_part1(int bid, int target) { | |
int left=1, right=target, middle; | |
while(left < right) { | |
middle = (left+right)/2; | |
if (bid*middle == target) return middle; | |
else if (bid*middle < target) left = middle+1; | |
else right = middle; | |
} | |
return right; | |
} | |
// https://cp-algorithms.com/algebra/chinese-remainder-theorem.html | |
ll chinese_remainder(vi &nums, vi &rems) { | |
/* | |
x = ( ∑ (rems[i]*pp[i]*inv[i]) ) % prod | |
Where 0 <= i <= n-1 | |
rems[i] is given array of remainders | |
prod is product of all given numbers | |
prod = nums[0] * nums[1] * ... * nums[k-1] | |
pp[i] is product of all divided by nums[i] | |
pp[i] = prod / nums[i] | |
inv[i] = Modular Multiplicative Inverse of pp[i] with respect to nums[i] | |
*/ | |
ll prod = 1; | |
fore(n, nums) prod *= n; | |
vll pp; | |
fore(n, nums) pp.pb(prod/n); | |
vll inv; | |
forn(i, 0, nums.size()) inv.pb(mod_mult_inverse(pp[i], nums[i])); | |
ll x = 0; | |
forn(i, 0, nums.size()) x += (rems[i]*pp[i]*inv[i]); | |
return x % prod; | |
} | |
// https://www.geeksforgeeks.org/multiplicative-inverse-under-modulo-m/ | |
ll mod_mult_inverse(ll a, ll m) { | |
if (m == 1) return 0; | |
ll m0 = m; | |
ll y = 0, x = 1; | |
while (a > 1) { | |
// q is quotient | |
ll q = a / m; | |
ll t = m; | |
// m is remainder now, process same as Euclid's algo | |
m = a % m, a = t; | |
t = y; | |
// Update y and x | |
y = x - q * y; | |
x = t; | |
} | |
// Make x positive | |
if (x < 0) x += m0; | |
return x; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment