Advertisement
Guest User

Untitled

a guest
Dec 22nd, 2019
441
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.62 KB | None | 0 0
  1. import re
  2. import sympy
  3. from collections import deque
  4.  
  5. # Stolen from https://www.geeksforgeeks.org/modular-exponentiation-python/
  6. def modInverse(a, m):
  7.     m0 = m
  8.     y = 0
  9.     x = 1
  10.     if m == 1:
  11.         return 0
  12.     while a > 1:
  13.         # q is quotient
  14.         q = a // m
  15.         t = m
  16.         # m is remainder now, process
  17.         # same as Euclid's algo
  18.         m = a % m
  19.         a = t
  20.         t = y
  21.         # Update x and y
  22.         y = x - q * y
  23.         x = t
  24.     # Make x positive
  25.     if x < 0:
  26.         x = x + m0
  27.     return x
  28.  
  29.  
  30. read = open("inputs/22.txt").read().strip()
  31. lines = read.strip().split("\n")
  32. deck = deque(range(10007))
  33. for i, line in enumerate(lines):
  34.     if line == "deal into new stack":
  35.         deck = deque(reversed(deck))
  36.     else:
  37.         num, = map(int, re.findall(r"-?\d+", line))
  38.         if line.startswith("deal with increment "):
  39.             arr = [-1] * len(deck)
  40.             dealt = 0
  41.             for j in range(0, 10 ** 9, num):
  42.                 arr[j % len(arr)] = deck.popleft()
  43.                 dealt += 1
  44.                 if dealt == len(arr):
  45.                     break
  46.             deck = deque(arr)
  47.         elif line.startswith("cut "):
  48.             deck.rotate(-num)
  49.         else:
  50.             assert False
  51. print("Part1", deck.index(2019))
  52.  
  53.  
  54. def getEquation(deckSize):
  55.     curr = sympy.Symbol("x", integer=True)
  56.     for line in reversed(lines):
  57.         if line == "deal into new stack":
  58.             curr = deckSize - 1 - curr
  59.         else:
  60.             num, = map(int, re.findall(r"-?\d+", line))
  61.             if line.startswith("deal with increment "):
  62.                 # curr maps to curr * num % deckSize
  63.                 # So to undo the step need to find num^-1 % deckSize
  64.                 # Sympy can't handle simplifying the mods so we do it all at once in the end
  65.                 num_inv = modInverse(num, deckSize)
  66.                 curr = curr * num_inv
  67.             elif line.startswith("cut "):
  68.                 curr += num
  69.             else:
  70.                 assert False
  71.     return sympy.simplify(curr % deckSize)
  72.  
  73.  
  74. # Double check that this equation indeeds map my part 1 answer back to 2019
  75. print(getEquation(10007))
  76. x = 3939
  77. assert (
  78.     2019
  79.     == (
  80.         1315392026111080230451006564378314839352784895845592294250786878653195721500650716576276684844395334211426149137983383398423195398120918156699848671232000000000
  81.         * x
  82.         + 3517
  83.     )
  84.     % 10007
  85. )
  86.  
  87. # Actual part 2
  88. m = 119315717514047
  89. print("Part2")
  90. print(getEquation(m))
  91. # So the above maps a*x + b, which we copy down here:
  92. a = 2316501396575371573016884678972948408477118784181279403146479358987429110680017215948234886737944359959659404860298247604585300479030678380891857145974915848363346190901774010806108688385389566982151447255088144603207909635702542420948170594137083913460644529332734085415134701115605467400065023156837188485481208699186149052054077337449224873105350769960052638271121814070165393889413968776953196804435429662708235469836808282548171995262149191170173274077122837548442192037743662496368320149073154335633490074785580236768632505924285263685560816378241646170581426929350719949412438638592000000000
  93. b = 81917208448684
  94. N = 101741582076661
  95. # Each a * x + b will undo one shuffle. Need to iterate N times
  96. #
  97. #   a * x +       b
  98. # a^2 * x + a   * b +       b
  99. # a^3 * x + a^2 * b + a   * b  +     b
  100. # a^4 * x + a^3 * b + a^2 * b  + a * b + b
  101. # ...
  102. # a^N * x + (a^(N-1) + a^(N-2) + ... + 1) * b
  103. #
  104. # The geometric sum can also be simplified to (a^N - 1) / (a - 1). Thus:
  105. print(
  106.     "Part2", (pow(a, N, m) * 2020 + b * (pow(a, N, m) - 1) * modInverse(a - 1, m)) % m
  107. )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement