Project Euler Problem 793

Let Si be an integer sequence produced with the following pseudo-random number generator: - S0 = 290797 - S{i+1} = Si ^2

Project Euler Problem 793

Solution

Answer: 475808650131120

Let

$$S_0=290797,\qquad S_{i+1}=S_i^2 \bmod 50515093$$

and define

$$P(n)={S_iS_j \mid 0\le i<j<n}.$$

There are

$$N=\binom n2$$

pairwise products. Since $N$ is odd for $n=1{,}000{,}003$, the median is the unique element with exactly $N//2$ products below it.

We are asked for

$$M(1{,}000{,}003).$$


1. Mathematical analysis

Step 1: Generate and sort the sequence

The pseudo-random generator produces positive integers less than $50515093$.

Let

$$A = \text{sorted}(S_0,S_1,\dots,S_{n-1}).$$

Sorting is crucial because it lets us count products efficiently.


Step 2: Convert the median problem into a counting problem

Define

$$f(x)=#{(i,j): i<j,\ A_iA_j\le x}.$$

Then $f(x)$ is monotone increasing.

If we can compute $f(x)$ quickly, then the median is the smallest $x$ such that

$$f(x)\ge \frac{N+1}{2}.$$

For

$$N=\binom{1{,}000{,}003}{2}=500002500003,$$

the target rank is

$$K=\frac{N+1}{2}=250001250002.$$

So we seek the smallest integer $x$ with

$$f(x)\ge K.$$


Step 3: Two-pointer counting

Because $A$ is sorted, we can count pairs in linear time.

Fix $i$. We want the largest $j>i$ satisfying

$$A_iA_j\le x.$$

As $i$ increases, this maximal $j$ never increases, so we use a decreasing pointer.

Algorithm:

  • Start $j=n-1$.

  • For each $i$:

  • While $A_iA_j>x$, decrement $j$.

  • Then all indices $i+1,\dots,j$ work.

  • Add $j-i$ to the count.

This computes $f(x)$ in $O(n)$.


Products range from

$$0 \le A_iA_j \le A_{n-1}A_{n-2}.$$

Since $f(x)$ is monotone, binary search finds the median in about 51 iterations because the search range is below $2^{52}$.

Total complexity:

  • Sorting: $O(n\log n)$
  • Each count: $O(n)$
  • Binary search: $O(n\log V)$

This is fast enough for $n=1{,}000{,}003$.


2. Python implementation

MOD = 50515093
N = 1_000_003

# ------------------------------------------------------------
# Generate the sequence
# ------------------------------------------------------------
S = [0] * N

x = 290797
for i in range(N):
    S[i] = x
    x = (x * x) % MOD

# ------------------------------------------------------------
# Sort values
# ------------------------------------------------------------
A = sorted(S)

# Number of pairwise products
total_pairs = N * (N - 1) // 2

# We want the lower/true median rank (1-based)
target = total_pairs // 2 + 1

# ------------------------------------------------------------
# Count how many pairs have product <= value
# ------------------------------------------------------------
def count_leq(value):
    count = 0
    j = N - 1

    for i, a in enumerate(A):

        while i < j and a * A[j] > value:
            j -= 1

        if j <= i:
            break

        count += (j - i)

    return count

# ------------------------------------------------------------
# Binary search for the median product
# ------------------------------------------------------------
lo = 0
hi = A[-1] * A[-2]

while lo < hi:
    mid = (lo + hi) // 2

    if count_leq(mid) >= target:
        hi = mid
    else:
        lo = mid + 1

print(lo)

3. Code walkthrough

Sequence generation

x = 290797
for i in range(N):
    S[i] = x
    x = (x * x) % MOD

This exactly follows the recurrence definition.


Sorting

A = sorted(S)

Sorted order enables monotone two-pointer counting.


Counting pairs

while i < j and a * A[j] > value:
    j -= 1

For each fixed $i$, move $j$ downward until the product constraint holds.

Then:

count += (j - i)

because every index between $i+1$ and $j$ works.

Overall runtime is linear because $j$ only decreases.


if count_leq(mid) >= target:
    hi = mid
else:
    lo = mid + 1

This finds the smallest value whose rank is at least the median rank.


4. Verification on the given examples

For $n=3$, the algorithm returns:

$$3878983057768$$

matching the statement.

For $n=103$, it returns:

$$492700616748525$$

also matching the statement.

So the implementation is validated.


5. Final computation

Running the full computation for $n=1{,}000{,}003$ gives:

$$475808650131120$$

Answer: 475808650131120