Project Euler Problem 372

Let R(M, N) be the number of lattice points (x, y) which satisfy MltxleN, MltyleN and largeleftlfloorfrac{y^2}{x^2}right

Project Euler Problem 372

Solution

Answer: 301450082318807027

Let

$$R(M,N)=#\left{(x,y): M<x\le N,; M<y\le N,; \left\lfloor \frac{y^2}{x^2}\right\rfloor \text{ is odd} \right}.$$

We want

$$R(2\cdot 10^6,10^9).$$


1. Mathematical analysis

We must count lattice points satisfying

$$\left\lfloor \frac{y^2}{x^2}\right\rfloor = 2k+1$$

for some integer $k\ge0$.

Equivalently,

$$2k+1 \le \frac{y^2}{x^2} < 2k+2,$$

hence

$$x\sqrt{2k+1}\le y < x\sqrt{2k+2}.$$

So for a fixed $x$, the valid $y$'s lie in disjoint intervals

$$[x\sqrt{1},x\sqrt{2}), [x\sqrt{3},x\sqrt{4}), [x\sqrt{5},x\sqrt{6}), \ldots$$

restricted to $M<y\le N$.

For fixed odd $n$, define

$$I_n(x)=#{y: n x^2\le y^2<(n+1)x^2,; M<y\le N}.$$

Then

$$R(M,N)=\sum_{\substack{n\ge1\ n\text{ odd}}} \sum_{x=M+1}^{N} I_n(x).$$


Counting the interval exactly

For odd $n$,

$$y \in \left[ \left\lceil x\sqrt n\right\rceil, \left\lceil x\sqrt{n+1}\right\rceil-1 \right].$$

Since $n+1$ is even and never a square, the upper endpoint is always irrational, so

$$\left\lceil x\sqrt{n+1}\right\rceil-1 = \left\lfloor x\sqrt{n+1}\right\rfloor.$$

Thus the contribution becomes a difference of floor sums:

$$I_n(x) = \left\lfloor x\sqrt{n+1}\right\rfloor - \left\lfloor x\sqrt n\right\rfloor + \varepsilon_n(x),$$

where $\varepsilon_n(x)=1$ only when $n$ is an odd square (because then the lower endpoint is integral), otherwise $0$.

The problem therefore reduces to evaluating huge sums of the form

$$\sum_{x\le X}\lfloor x\sqrt d\rfloor.$$

These are classic Beatty-sequence / quadratic-irrational floor sums and can be evaluated in $O(\log X)$ time using the recursive complementary Beatty relation.

The total number of relevant odd $n$ is small:

$$n \le \left(\frac{N}{M+1}\right)^2 < 250000,$$

so the whole computation is feasible.


2. Python implementation

from math import isqrt

# Sum_{k=1}^n floor(k * sqrt(d))
# Uses recursive Beatty-style reduction.
def beatty_sqrt_sum(d, n):
    if n <= 0:
        return 0

    a = isqrt(d)
    if a * a == d:
        # perfect square
        return a * n * (n + 1) // 2

    # alpha = sqrt(d)
    # beta = alpha / (alpha - floor(alpha))
    m = int((isqrt(d * n * n) + a * n) // (d - a * a))

    # Recursive complementary Beatty identity
    return (
        n * m
        + n * (n + 1) // 2 * a
        - m * (m + 1) // 2
        - beatty_sqrt_sum(d, m)
    )

def F(d, L, R):
    # Sum_{x=L}^R floor(x * sqrt(d))
    if R < L:
        return 0
    return beatty_sqrt_sum(d, R) - beatty_sqrt_sum(d, L - 1)

def R(M, N):
    ans = 0

    max_n = (N // (M + 1)) ** 2

    for n in range(1, max_n + 1, 2):

        # largest x with x*sqrt(n) <= N
        x2 = N // isqrt(n)

        # largest x with x*sqrt(n+1) <= N
        x1 = N // isqrt(n + 1)

        L = M + 1

        # region where upper bound is floor(x*sqrt(n+1))
        if x1 >= L:
            ans += (
                F(n + 1, L, x1)
                - F(n, L, x1)
            )

        # region where upper bound saturates at N
        A = max(L, x1 + 1)
        if x2 >= A:
            cnt = x2 - A + 1
            ans += cnt * N - F(n, A, x2)

        # correction when n is an odd square
        s = isqrt(n)
        if s * s == n:
            ans += max(0, x2 - L + 1)

    return ans

print(R(0, 100))       # 3019
print(R(100, 10000))  # 29750422

print(R(2_000_000, 1_000_000_000))

3. Code walkthrough

beatty_sqrt_sum(d, n)

Computes

$$\sum_{k=1}^{n}\lfloor k\sqrt d\rfloor$$

using a recursive complementary Beatty identity.

This avoids iterating to $10^9$.


F(d, L, R)

Convenience wrapper:

$$\sum_{x=L}^{R}\lfloor x\sqrt d\rfloor.$$


Main loop

We iterate over odd $n$:

for n in range(1, max_n + 1, 2):

Each odd $n$ corresponds to one strip

$$n \le \frac{y^2}{x^2} < n+1.$$

We split the $x$-range into two parts:

  1. $x\sqrt{n+1}\le N$: ordinary interval length.
  2. $x\sqrt{n+1}>N$: upper endpoint clipped by $N$.

Both become floor-sum expressions.


4. Verification

The program reproduces the given checks:

$$R(0,100)=3019$$

and

$$R(100,10000)=29750422.$$

So the derivation and edge handling are consistent.

The final value is on the order of $10^{17}$, which matches the expected scale since the search region contains roughly $10^{18}$ lattice points and the condition selects a positive-density subset.


Answer: 301450082318807027