Challenge: The Bouncing Flying Ball
Subdomeniu: Number Theory (number-theory)
Scor cont: 100.0 / 100
Submission status: Accepted
Submission score: 1.0
Submission ID: 464775517
Limbaj: python3
Link challenge: https://www.hackerrank.com/challenges/the-bouncing-flying-ball/problem
Cerinta
Sergey and Chen are locked in a rectangular box of Dimension L\*W\*H. Evil Larry has put a machine which is located at a point inside the box (p,q,r) which starts shooting balls in every direction (dx,dy,dz) where
-N ≤ dx, dy, dz ≤ N except (0, 0, 0)
such that the ball goes through (p, q, r) -> (p + dx, q + dy, r + dz) -> (p + 2dx, q + 2dy, r + 2dz) and so on.
so, a total of (2N + 1)<sup>3</sup> - 1 balls are fired. Sergey is standing at (a,b,c) and Chen is standing at (d,e,f). Provided all the balls follow reflection property and have constant velocity and gravity is not taken into account, can you tell how many balls are caught by Sergey and Chen? Sergey and Chen can catch the ball if it passes through the point at which they are standing.
**Input Format**
The first line contains the number of test cases, T lines follow, each containing a testcase.
Each testcase contains 13 integers in the following order
L W H a b c d e f p q r N
**Output Format**
For each test case please output two integers indicating the number of balls that are caught by Sergey and C, respectively.
**Constraints**
T = 1
1 ≤ L, W, H, a, b, c, d, e, f, p, q, r, N ≤ 50
**Sample Input**
1
3 3 3 1 1 1 1 1 2 2 2 2 1
**Sample Output**
8 4
**Explanation**
Here, L, W, H = (3, 3, 3), Sergey is at (1, 1, 1) and Chen is at (1, 1, 2) and the machine Larry put is at (2, 2, 2).
Balls are thrown at -1 ≤ x, y, z ≤ 1 from (2, 2, 2).
+ (-1, -1, -1): (2, 2, 2)->(1, 1, 1) Sergey
+ (-1, -1, 0): (2, 2, 2)->(1, 1, 2) Chen
+ (-1, -1, 1): (2, 2, 2)->(1, 1, 3)->(0, 0, 2)->(1, 1, 1) Sergey
+ (-1, 0, -1): (2, 2, 2)->(1, 2, 1)->(0, 2, 0)->(1, 2, 1)->(2, 2, 2)->(3, 2, 3)->...
+ (-1, 0, 0): (2, 2, 2)->(1, 2, 2)->(0, 2, 2)->(1, 2, 2)->(2, 2, 2)->(3, 2, 2)->...
+ (-1, 0, 1): (2, 2, 2)->(1, 2, 3)->(0, 2, 2)->(1, 2, 1)->(2, 2, 0)->(3, 2, 1)->...
+ (-1, 1, -1): (2, 2, 2)->(1, 3, 1)->(0, 2, 0)->(1, 1, 1) Sergey
+ (-1, 1, 0): (2, 2, 2)->(1, 3, 2)->(0, 2, 2)->(1, 1, 2) Chen
+ (-1, 1, 1): (2, 2, 2)->(1, 3, 3)->(0, 2, 2)->(1, 1, 1) Sergey
+ (0, *, *): x-coordinate never changed
+ (1, -1, -1): (2, 2, 2)->(3, 1, 1)->(2, 0, 0)->(1, 1, 1) Sergey
+ (1, -1, 0): (2, 2, 2)->(3, 1, 2)->(2, 0, 2)->(1, 1, 2) Chen
+ (1, -1, 1): (2, 2, 2)->(3, 1, 3)->(2, 0, 2)->(1, 1, 1) Sergey
+ (1, 0, -1): (2, 2, 2)->(3, 2, 1)->(2, 2, 0)->(1, 2, 1)->(0, 2, 2)->...
+ (1, 0, 0): (2, 2, 2)->(3, 2, 2)->(2, 2, 2)->(1, 2, 2)->(0, 2, 2)->...
+ (1, 0, 1): (2, 2, 2)->(3, 2, 3)->(2, 2, 2)->(1, 2, 1)->(0, 2, 0)->...
+ (1, 1, -1): (2, 2, 2)->(3, 3, 1)->(2, 2, 0)->(1, 1, 1) Sergey
+ (1, 1, 0): (2, 2, 2)->(3, 3, 2)->(2, 2, 2)->(1, 1, 2) Chen
+ (1, 1, 1): (2, 2, 2)->(3, 3, 3)->(2, 2, 2)->(1, 1, 1) Sergey
Cod sursa
# Enter your code here. Read input from STDIN. Print output to STDOUT
from math import gcd
def solutionExists(L, x, dx):
"""
Exists k such that x = dx * k (mod L)
"""
if dx == 0:
return x == 0
return x % gcd(L, dx) == 0
diafant_cache = {}
def diafantSolution(a, b, c):
"""
Find a solution of ax + by = c in a form
(x,y) = (x0,y0)+t(x1,y1)
Existence of the solution must be verified in advance.
a != 0 and b != 0
"""
key = f"{a},{b},{c}"
if key in diafant_cache:
return diafant_cache[key]
a1, b1 = 1, 0
a2, b2 = 0, 1
while b:
d = (a - a % b) // b
a, b = b, a - d * b
a1, b1 = b1, a1 - d * b1
a2, b2 = b2, a2 - d * b2
x0, y0 = a1 * c // a, a2 * c // a
x1, y1 = b1, b2
if x1 < 0:
x1, y1 = -x1, -y1
while x0 < 0:
x0 += x1
y0 += y1
while x0 - x1 > 0:
x0 -= x1
y0 -= y1
diafant_cache[key] = (x0, y0, x1, y1)
return x0, y0, x1, y1
def step(L, x, dx):
start = 0
while start <= L and start * dx % L != x:
start += 1
if start == L + 1:
return None
step = 1
while (start + step) * dx % L != x:
step += 1
return start, step
def dxAndSteps(L, xs, xm, N):
result = {}
for dx in range(-N, N + 1):
if dx % L in result:
continue
r = []
if solutionExists(L, xs, dx):
r.append(step(L, xs, dx))
if xs != xm:
if solutionExists(L, xm, dx):
r.append(step(L, xm, dx))
if r:
result[dx % L] = r
return result
def hit(nxs, nys, nzs):
for nx in nxs:
startX, stepX = nx
for ny in nys:
startY, stepY = ny
if stepX == stepY and startX != startY:
continue
for nz in nzs:
startZ, stepZ = nz
if stepX == stepZ and startX != startZ:
continue
if stepZ == stepY and startZ != startY:
continue
m14 = stepX * (startZ - startY)
m24 = stepY * (startZ - startX)
m34 = stepZ * (startY - startX)
gcd123 = gcd(stepX * gcd(stepY, stepZ), stepY * stepZ)
if m14 % gcd123 == m24 % gcd123 == m34 % gcd123 == 0:
return True
return False
def shortestPath(nxs, nys, nzs, limit):
result = limit
for nx in nxs:
startX, stepX = nx
for ny in nys:
startY, stepY = ny
if stepX == stepY and startX != startY:
continue
for nz in nzs:
startZ, stepZ = nz
if stepX == stepZ and startX != startZ:
continue
if stepZ == stepY and startZ != startY:
continue
x0, _, x1, _ = diafantSolution(stepX, -stepY, startY - startX)
m14 = stepX * (startZ - startY)
m24 = stepY * (startZ - startX)
m34 = stepZ * (startY - startX)
gcd123 = gcd(stepX * gcd(stepY, stepZ), stepY * stepZ)
if m14 % gcd123 == m24 % gcd123 == m34 % gcd123 == 0:
z0, _, _, _ = diafantSolution(-stepZ, stepX * x1, startZ - startX - stepX * x0)
newRes = startZ + stepZ * z0
result = min(result, newRes)
return result
def solve(L, W, H, x1, y1, z1, x2, y2, z2, x0, y0, z0, N):
L += L
W += W
H += H
x1s, x1m = (x1 - x0) % L, (L - x1 - x0) % L
x2s, x2m = (x2 - x0) % L, (L - x2 - x0) % L
y1s, y1m = (y1 - y0) % W, (W - y1 - y0) % W
y2s, y2m = (y2 - y0) % W, (W - y2 - y0) % W
z1s, z1m = (z1 - z0) % H, (H - z1 - z0) % H
z2s, z2m = (z2 - z0) % H, (H - z2 - z0) % H
DX1 = dxAndSteps(L, x1s, x1m, N)
DY1 = dxAndSteps(W, y1s, y1m, N)
DZ1 = dxAndSteps(H, z1s, z1m, N)
DX2 = dxAndSteps(L, x2s, x2m, N)
DY2 = dxAndSteps(W, y2s, y2m, N)
DZ2 = dxAndSteps(H, z2s, z2m, N)
result1 = 0
result2 = 0
limit = L * W * H
cache = {}
for dxx in range(-N, N + 1):
for dyy in range(-N, N + 1):
gxy = gcd(dxx, dyy)
for dzz in range(-N, N + 1):
if dxx == dyy == dzz == 0:
continue
g = gcd(gxy, dzz)
dx, dy, dz = (dxx // g) % L, (dyy // g) % W, (dzz // g) % H
key = (dx * limit + dy) * limit + dz
if key in cache:
r1, r2 = cache[key]
result1 += r1
result2 += r2
continue
firstHit, secondHit = False, False
if dx in DX1 and dy in DY1 and dz in DZ1:
firstHit = hit(DX1[dx], DY1[dy], DZ1[dz])
if dx in DX2 and dy in DY2 and dz in DZ2:
secondHit = hit(DX2[dx], DY2[dy], DZ2[dz])
if firstHit and secondHit:
N1 = shortestPath(DX1[dx], DY1[dy], DZ1[dz], limit = limit)
N2 = shortestPath(DX2[dx], DY2[dy], DZ2[dz], limit = N1 + 1)
if N1 < N2:
result1 += 1
cache[key] = (1, 0)
else:
result2 += 1
cache[key] = (0, 1)
elif firstHit:
result1 += 1
cache[key] = (1, 0)
elif secondHit:
result2 += 1
cache[key] = (0, 1)
return result1, result2
if __name__ == "__main__":
input()
L, W, H, x1, y1, z1, x2, y2, z2, x0, y0, z0, N = list(map(int, input().split()))
r1, r2 = solve(L = L, W = W, H = H, x1 = x1, y1 = y1, z1 = z1, x2 = x2, y2 = y2, z2 = z2, x0 = x0, y0 = y0, z0 = z0, N = N)
print(f"{r1} {r2}")
HackerRank Number Theory – The Bouncing Flying Ball
