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}

Project Euler Problem 816

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