diff --git a/2020/day13_bus.py b/2020/day13_bus.py index d1a4877..f1d5b24 100644 --- a/2020/day13_bus.py +++ b/2020/day13_bus.py @@ -36,6 +36,53 @@ def solve_part_1(notes) -> int: def solve_part_2(notes) -> int: + split = notes[1].split(",") + modulos = [] + remainders = [] + for position, bus_index in enumerate(split): + if bus_index == "x": + continue + bus_index = int(bus_index) + modulos.append(bus_index) + remainders.append(bus_index - position) + return chinese_remainder(modulos, remainders) + + +def chinese_remainder(modulos, remainders): + """List of modulos, then list of remainders""" + # https://rosettacode.org/wiki/Chinese_remainder_theorem#Python + # License: https://www.gnu.org/licenses/old-licenses/fdl-1.2.html + total = 0 + prod = functools.reduce(lambda a, b: a * b, modulos) + for modulo, remainder in zip(modulos, remainders): + p = prod // modulo + total += remainder * mul_inv(p, modulo) * p + return total % prod + + +def mul_inv(a, b): + # https://rosettacode.org/wiki/Chinese_remainder_theorem#Python + # License: https://www.gnu.org/licenses/old-licenses/fdl-1.2.html + b0 = b + x0, x1 = 0, 1 + if b == 1: + return 1 + while a > 1: + q = a // b + a, b = b, a % b + x0, x1 = x1 - q * x0, x0 + if x1 < 0: + x1 += b0 + return x1 + + +if __name__ == "__main__": + n = [3, 5, 7] + a = [2, 3, 2] + print(chinese_remainder(n, a)) + + +def solve_part_2_iterative(notes) -> int: """Works but far too slow for the real deal.""" split = notes[1].split(",") buses = list(map(int, filter(lambda bus: bus != "x", split))) @@ -66,4 +113,4 @@ if __name__ == "__main__": main("inputs/day13-test4", None, 779210) main("inputs/day13-test5", None, 1261476) main("inputs/day13-test6", None, 1202161486) - main("inputs/day13", 4315) + main("inputs/day13", 4315, 556100168221141)