Project Euler Problem 816
We create an array of points Pn in a two dimensional plane using the following random number generator: s0=290797 s{n+1}
Solution
Answer: 20.880613018
To solve this efficiently for $k = 2{,}000{,}000$, a brute-force $O(n^2)$ comparison is impossible ($\sim 2\times10^{12}$ pairs).
The correct approach is the classic closest pair of points sweep-line algorithm:
- Generate all points using the given pseudo-random sequence.
- Sort points by $x$-coordinate.
- Maintain an active set ordered by $y$-coordinate.
- Only compare points within the current best distance.
The algorithm runs in $O(n \log n)$.
Python implementation used:
from math import sqrt
import bisect
import math
MOD = 50515093
n = 2000000
# Generate points
pts = [None] * n
s = 290797
vals = [0] * (2 * n)
for i in range(2 * n):
vals[i] = s
s = (s * s) % MOD
for i in range(n):
pts[i] = (vals[2 * i], vals[2 * i + 1])
# Sort by x-coordinate
pts.sort()
best2 = float('inf')
# Active set sorted by y-coordinate: (y, x)
active = []
left = 0
for x, y in pts:
d = math.sqrt(best2) if best2 < float('inf') else float('inf')
# Remove points too far in x-direction
while x - pts[left][0] > d:
xx, yy = pts[left]
idx = bisect.bisect_left(active, (yy, xx))
active.pop(idx)
left += 1
# Candidate points within y-range
lo = bisect.bisect_left(active, (y - d, -10**18))
hi = bisect.bisect_right(active, (y + d, 10**18))
for yy, xx in active[lo:hi]:
dx = x - xx
dy = y - yy
ds = dx * dx + dy * dy
if ds < best2:
best2 = ds
d = math.sqrt(best2)
bisect.insort(active, (y, x))
answer = math.sqrt(best2)
print(f"{answer:.12f}")
Verification against the sample:
- The program reproduces:
$$d(14)=546446.466846479$$
as stated in the problem.
The computed value for $d(2000000)$ is:
$$20.8806130178211\ldots$$
Rounded to 9 decimal places:
Answer: 20.880613018