Problem 611: Hallway of Square Steps

View on Project Euler

Project Euler Problem 611 Solution

EulerSolve provides an optimized solution for Project Euler Problem 611, Hallway of Square Steps, with C++, Python, Java, and a step-by-step mathematical explanation.

Problem Summary For every pair of distinct positive squares \(a^2 \lt b^2\), Peter toggles door \(n=a^2+b^2\), provided \(n\le N\). After all actions, door \(n\) remains open exactly when the number of strict representations $$u(n)=\#\left\{(a,b)\in \mathbb{Z}_{>0}^2 : a \lt b,\ a^2+b^2=n\right\}$$ is odd. Therefore $$F(N)=\#\left\{n\le N : u(n)\equiv 1 \pmod 2\right\}.$$ The real input is \(N=10^{12}\), so enumerating all square pairs is far too slow. The implementation instead turns the problem into a classification of prime exponents. Mathematical Approach The central object is the classical sum-of-two-squares counting function over all signs and orders. Step 1: Relate Door Toggles to the Classical Representation Count Let $$r_2(n)=\#\left\{(x,y)\in \mathbb{Z}^2 : x^2+y^2=n\right\}.$$ Every strict positive representation \(a \lt b\) generates eight ordered signed solutions: \((\pm a,\pm b)\) and \((\pm b,\pm a)\). Two degenerate situations contribute only four solutions: $$n=c^2 \quad \text{gives} \quad (\pm c,0),(0,\pm c),$$ $$n=2c^2 \quad \text{gives} \quad (\pm c,\pm c).$$ So if we define $$s(n)= \begin{cases} 1,&\text{if } n \text{ is a square or twice a square},\\ 0,&\text{otherwise}, \end{cases}$$ then $$r_2(n)=8u(n)+4s(n),$$ hence $$\frac{r_2(n)}{4}=2u(n)+s(n).$$ This identity is the bridge from door toggling to arithmetic parity....

Detailed mathematical approach

Problem Summary

For every pair of distinct positive squares \(a^2 \lt b^2\), Peter toggles door \(n=a^2+b^2\), provided \(n\le N\). After all actions, door \(n\) remains open exactly when the number of strict representations

$$u(n)=\#\left\{(a,b)\in \mathbb{Z}_{>0}^2 : a \lt b,\ a^2+b^2=n\right\}$$

is odd. Therefore

$$F(N)=\#\left\{n\le N : u(n)\equiv 1 \pmod 2\right\}.$$

The real input is \(N=10^{12}\), so enumerating all square pairs is far too slow. The implementation instead turns the problem into a classification of prime exponents.

Mathematical Approach

The central object is the classical sum-of-two-squares counting function over all signs and orders.

Step 1: Relate Door Toggles to the Classical Representation Count

Let

$$r_2(n)=\#\left\{(x,y)\in \mathbb{Z}^2 : x^2+y^2=n\right\}.$$

Every strict positive representation \(a \lt b\) generates eight ordered signed solutions: \((\pm a,\pm b)\) and \((\pm b,\pm a)\). Two degenerate situations contribute only four solutions:

$$n=c^2 \quad \text{gives} \quad (\pm c,0),(0,\pm c),$$

$$n=2c^2 \quad \text{gives} \quad (\pm c,\pm c).$$

So if we define

$$s(n)= \begin{cases} 1,&\text{if } n \text{ is a square or twice a square},\\ 0,&\text{otherwise}, \end{cases}$$

then

$$r_2(n)=8u(n)+4s(n),$$

hence

$$\frac{r_2(n)}{4}=2u(n)+s(n).$$

This identity is the bridge from door toggling to arithmetic parity.

Step 2: Use the Sum-of-Two-Squares Theorem

Write the factorization of \(n\) as

$$n=2^a\prod_{p\equiv 1 \pmod 4} p^{\alpha_p}\prod_{q\equiv 3 \pmod 4} q^{\beta_q}.$$

If any prime \(q\equiv 3 \pmod 4\) has odd exponent, then \(n\) is not representable as a sum of two squares at all, so \(r_2(n)=0\) and \(u(n)\) is even. The only interesting numbers are therefore

$$n=2^a\prod_{p\equiv 1 \pmod 4} p^{\alpha_p}\prod_{q\equiv 3 \pmod 4} q^{2\gamma_q}.$$

For such \(n\), the standard formula becomes

$$r_2(n)=4\prod_{p\equiv 1 \pmod 4}(\alpha_p+1).$$

Define

$$R(n)=\prod_{p\equiv 1 \pmod 4}(\alpha_p+1).$$

Then the parity condition is simply

$$R(n)=2u(n)+s(n).$$

So the question becomes: for which exponent patterns is \((R(n)-s(n))/2\) odd?

Step 3: Family A, the Non-Degenerate Case

First assume \(s(n)=0\), meaning \(n\) is neither a square nor twice a square. Then \(u(n)\) is odd exactly when

$$R(n)\equiv 2 \pmod 4.$$

Because each factor \(\alpha_p+1\) is odd when \(\alpha_p\) is even and even when \(\alpha_p\) is odd, the product can be \(2 \pmod 4\) only when exactly one factor contributes a single power of \(2\) and every other factor remains odd. So there must be exactly one prime \(p\equiv 1 \pmod 4\) with odd exponent, and that exponent must satisfy

$$\alpha_p+1\equiv 2 \pmod 4 \iff \alpha_p\equiv 1 \pmod 4.$$

Therefore the non-degenerate doors that remain open are exactly those of the form

$$n=p^{4t+1}m^2 \quad \text{or} \quad n=2p^{4t+1}m^2,$$

where \(p\equiv 1 \pmod 4\) and \(p\nmid m\). This is the first family counted by the implementation.

Step 4: Family B, the Square / Twice-Square Correction

Now assume \(s(n)=1\). That means every exponent \(\alpha_p\) is even, so \(n\) is either a square or twice a square. We can write it uniquely as

$$n=2^a m^2,\qquad m \text{ odd}.$$

Since \(u(n)\) is odd exactly when

$$R(n)\equiv 3 \pmod 4,$$

we inspect each factor with \(\alpha_p=2\delta_p\). Then

$$\alpha_p+1=2\delta_p+1\equiv \begin{cases} 1 \pmod 4,&\delta_p \text{ even},\\ 3 \pmod 4,&\delta_p \text{ odd}. \end{cases}$$

So \(R(n)\equiv 3 \pmod 4\) exactly when an odd number of primes \(p\equiv 1 \pmod 4\) occur to odd exponent in the odd square root \(m\). That produces the second family:

$$n=2^a m^2,\qquad m \text{ odd},$$

with the parity filter “the number of primes \(p\equiv 1 \pmod 4\) occurring to odd exponent in \(m\) is odd.”

Step 5: Count Family A Efficiently

Let \(\pi_1(x)\) denote the number of primes \(p\le x\) with \(p\equiv 1 \pmod 4\). For the even-\(2\)-adic half of family A, we count numbers

$$n=p^{4t+1}m^2,\qquad p\equiv 1 \pmod 4,\ p\nmid m,\ n\le N.$$

For the first exponent layer \(p^1\), the contribution of one prime is

$$\#\{m : p m^2\le N,\ p\nmid m\}=\left\lfloor\sqrt{\frac{N}{p}}\right\rfloor-\left\lfloor\sqrt{\frac{N}{p^3}}\right\rfloor.$$

The first term is grouped by equal square-root quotients:

$$\sum_{p\equiv 1 \pmod 4}\left\lfloor\sqrt{\frac{N}{p}}\right\rfloor =\sum_{t\ge 1} t\left(\pi_1\left(\left\lfloor\frac{N}{t^2}\right\rfloor\right)-\pi_1\left(\left\lfloor\frac{N}{(t+1)^2}\right\rfloor\right)\right).$$

The subtraction by \(\left\lfloor\sqrt{N/p^3}\right\rfloor\) removes the forbidden choices where the square part already contains \(p\). Higher valid exponents \(p^5,p^9,\dots\) are sparse, so they are added directly through

$$\left\lfloor\sqrt{\frac{N}{p^{4t+1}}}\right\rfloor-\left\lfloor\sqrt{\frac{N}{p^{4t+3}}}\right\rfloor,\qquad t\ge 1.$$

If \(v_2(n)\) is odd, then \(n\) belongs to the second variant \(2p^{4t+1}m^2\). Multiplying by \(2\) gives a bijection with the even-\(v_2\) case at bound \(N/2\), so the same routine can be reused with \(N\) replaced by \(N/2\).

Step 6: Count Family B Efficiently

For family B, every valid odd \(m\le \sqrt{N}\) contributes all numbers

$$m^2,\ 2m^2,\ 4m^2,\ \dots,\ 2^a m^2\le N.$$

The number of admissible powers of \(2\) is

$$\left\lfloor \log_2\left(\frac{N}{m^2}\right)\right\rfloor+1.$$

So the remaining work is to know, for each odd \(m\), whether the count of primes \(p\equiv 1 \pmod 4\) appearing to odd exponent is odd or even.

Worked Example: \(N=100\)

The checkpoint \(F(100)=27\) follows cleanly from the classification.

Family A with even \(v_2\) gives

$$5,13,17,20,29,37,41,45,52,53,61,68,73,80,89,97,$$

so there are \(16\) such doors.

Family A with odd \(v_2\) is obtained by doubling the even-\(v_2\) doors up to \(50\), namely

$$10,26,34,40,58,74,82,90,$$

which contributes \(8\) more doors.

For family B, the odd candidates \(m\le 10\) are \(1,3,5,7,9\). Only \(m=5\) has an odd number of \(1 \pmod 4\) primes occurring to odd exponent, so it contributes

$$25,\ 50,\ 100,$$

hence \(3\) more doors. Therefore

$$F(100)=16+8+3=27.$$

How the Code Works

The C++, Python, and Java implementations all follow the same arithmetic decomposition. The Python entry point is only a thin wrapper around that same numerical strategy, so the mathematics is identical across languages.

The implementation first builds a prime-counting structure over the quotient values \(\lfloor N/i\rfloor\). It stores both the ordinary prime count \(\pi(x)\) and a weighted prime sum using the Dirichlet character

$$\chi_4(n)= \begin{cases} 0,&n \text{ even},\\ 1,&n\equiv 1 \pmod 4,\\ -1,&n\equiv 3 \pmod 4. \end{cases}$$

From these two tables it recovers

$$\pi_1(x)=\frac{(\pi(x)-1)+\sum_{p\le x}\chi_4(p)}{2},$$

which is exactly the count of primes \(p\le x\) with \(p\equiv 1 \pmod 4\).

With that tool in place, the implementation counts family A in three pieces: the grouped \(p^1\) layer, the correction that subtracts roots already divisible by the chosen prime, and the direct enumeration of the sparse higher layers \(p^5,p^9,\dots\). It then reuses the same routine at \(N/2\) to count the odd-\(v_2\) branch.

For family B, the implementation precomputes smallest prime factors up to \(\lfloor\sqrt{N}\rfloor\). Factoring each odd \(m\) reveals whether the number of primes \(p\equiv 1 \pmod 4\) occurring to odd exponent is odd. Whenever the parity condition holds, it adds

$$\left\lfloor \log_2\left(\frac{N}{m^2}\right)\right\rfloor+1$$

to the answer.

Finally, the implementation adds the even-\(v_2\) branch of family A, the corresponding odd-\(v_2\) branch obtained from the \(N/2\) bijection, and the family-B contribution.

Complexity Analysis

Let \(M=\lfloor\sqrt{N}\rfloor\). The smallest-prime-factor sieve and the parity table for odd \(m\) cost \(O(M\log\log M)\) time and \(O(M)\) memory. The family-B scan is linear in \(M\). The higher-power part of family A is very small because \(p^5\) already grows quickly.

The dominant work is the quotient-class prime-counting structure used to answer many values of \(\pi_1(x)\) efficiently. It stores \(O(M)\) quotient values and keeps the overall method practical for \(N=10^{12}\). So the implementation uses \(O(M)\) memory, and the runtime is dominated by the prime-counting preprocessing plus the linear-in-\(M\) auxiliary passes.

Footnotes and References

  1. Problem page: https://projecteuler.net/problem=611
  2. Fermat's theorem on sums of two squares: Wikipedia — Fermat's theorem on sums of two squares
  3. Sum of two squares function: Wikipedia — Sum of two squares function
  4. Dirichlet character: Wikipedia — Dirichlet character
  5. Prime-counting function: Wikipedia — Prime-counting function

Problem 611 source code

C++

#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdint>
#include <iostream>
#include <vector>

// Project Euler 611: count n <= N where #{0<a<b : a^2 + b^2 = n} is odd.
// Reduce to two arithmetic families via r2(n) and prime-exponent parity; count with a prime-counting sieve for p ≡ 1 (mod 4).

using u64 = std::uint64_t;
using i64 = std::int64_t;
using u128 = unsigned __int128;

static u64 isqrt_u64(u64 x) {
    u64 r = (u64)std::sqrt((long double)x);
    while ((u128)(r + 1) * (r + 1) <= x) ++r;
    while ((u128)r * r > x) --r;
    return r;
}

static int ilog2_u64(u64 x) {
    int r = 0;
    while ((1ULL << (r + 1)) <= x) ++r;
    return r;
}

static std::vector<int> sieve_primes_int(int n) {
    std::vector<bool> is_prime(n + 1, true);
    if (n >= 0) is_prime[0] = false;
    if (n >= 1) is_prime[1] = false;
    for (int p = 2; (u64)p * p <= (u64)n; ++p) {
        if (!is_prime[p]) continue;
        for (u64 j = (u64)p * p; j <= (u64)n; j += (u64)p) is_prime[(size_t)j] = false;
    }
    std::vector<int> primes;
    for (int i = 2; i <= n; ++i) {
        if (is_prime[i]) primes.push_back(i);
    }
    return primes;
}

struct PrimeCountMod4 {
    u64 n = 0;
    u64 sq = 0;
    std::vector<u64> vals;
    std::vector<u64> g_pi;
    std::vector<i64> g_chi;
    std::vector<int> id1;
    std::vector<int> id2;
    std::vector<int> primes;
    std::vector<i64> pref_chi_prime;

    static i64 chi_int(u64 x) {
        if ((x & 1ULL) == 0) return 0;
        return (x & 3ULL) == 1 ? 1 : -1;
    }

    static i64 sum_chi_1_to(u64 m) {
        // chi(k)=0 for even; for odd k, +1 if 1 mod4 else -1.
        const u64 c1 = (m + 3) / 4;
        const u64 c3 = (m + 1) / 4;
        return (i64)c1 - (i64)c3;
    }

    explicit PrimeCountMod4(u64 n_) : n(n_) {
        sq = (u64)std::sqrt((long double)n);
        primes = sieve_primes_int((int)sq);

        for (u64 l = 1; l <= n;) {
            const u64 w = n / l;
            vals.push_back(w);
            l = n / w + 1;
        }
        const int m = (int)vals.size();

        g_pi.resize(m);
        g_chi.resize(m);
        id1.assign((size_t)sq + 1, -1);
        id2.assign((size_t)sq + 1, -1);

        for (int i = 0; i < m; ++i) {
            const u64 w = vals[i];
            g_pi[i] = (w >= 2) ? (w - 1) : 0; // count of integers in [2..w]
            i64 s = (w >= 1) ? (sum_chi_1_to(w) - 1) : 0; // sum_{k=2..w} chi(k)
            g_chi[i] = s;
            if (w <= sq) id1[w] = i;
            else id2[n / w] = i;
        }

        pref_chi_prime.assign(primes.size() + 1, 0);
        for (std::size_t i = 0; i < primes.size(); ++i) {
            const int p = primes[i];
            pref_chi_prime[i + 1] = pref_chi_prime[i] + chi_int((u64)p);
        }

        for (std::size_t i = 0; i < primes.size(); ++i) {
            const u64 p = (u64)primes[i];
            const u64 p2 = p * p;
            if (p2 > n) break;
            const i64 chi_p = chi_int(p);

            for (int j = 0; j < m && vals[j] >= p2; ++j) {
                const u64 w = vals[j];
                const int idx = id(w / p);
                g_pi[j] -= g_pi[idx] - (u64)i;
                if (chi_p != 0) g_chi[j] -= chi_p * (g_chi[idx] - pref_chi_prime[i]);
            }
        }
    }

    inline int id(u64 x) const { return (x <= sq) ? id1[x] : id2[n / x]; }

    inline u64 pi(u64 x) const { return g_pi[id(x)]; }

    inline i64 sum_chi_primes(u64 x) const { return g_chi[id(x)]; }

    inline u64 pi1(u64 x) const {
        if (x < 5) return 0;
        const u64 pix = pi(x);
        const u64 odd_primes = pix - 1; // exclude prime 2
        const i64 s = sum_chi_primes(x);
        return (u64)((odd_primes + s) / 2);
    }
};

static std::vector<int> sieve_spf(int n) {
    std::vector<int> spf(n + 1, 0);
    std::vector<int> primes;
    primes.reserve(n / 10);
    for (int i = 2; i <= n; ++i) {
        if (spf[i] == 0) {
            spf[i] = i;
            primes.push_back(i);
        }
        for (int p : primes) {
            const long long v = 1LL * p * i;
            if (v > n) break;
            spf[(int)v] = p;
            if (p == spf[i]) break;
        }
    }
    return spf;
}

static u64 count_B(u64 N, const std::vector<uint8_t>& parity_odd1mod4) {
    const u64 lim = isqrt_u64(N);
    u64 ans = 0;
    // Unique parameterization for squares / twice-squares: n = 2^a * m^2 with m odd.
    for (u64 m = 1; m <= lim; m += 2) {
        if (!parity_odd1mod4[(size_t)m]) continue;
        const u64 base = m * m;
        const u64 t = N / base;
        ans += (u64)(ilog2_u64(t) + 1);
    }
    return ans;
}

static u64 count_A_even_v2(u64 N, const PrimeCountMod4& pc, const std::vector<int>& primes_small) {
    // a=0 term: sum_{p≡1(4)} (T - T/p), T=floor(sqrt(N/p)).
    u128 S1 = 0;
    const u64 tmax = isqrt_u64(N);
    for (u64 t = 1; t <= tmax; ++t) {
        const u64 R = N / (t * t);
        if (R < 5) break;
        const u64 L = N / ((t + 1) * (t + 1));
        const u64 cnt = pc.pi1(R) - pc.pi1(L);
        S1 += (u128)t * cnt;
    }

    u128 corr = 0;
    const u64 cbrtN = 10000; // for N up to 1e12 (exact)
    for (int p : primes_small) {
        if ((u64)p > cbrtN) break;
        if (p % 4 != 1) continue;
        const u64 T = isqrt_u64(N / (u64)p);
        corr += (u64)(T / (u64)p);
    }

    u128 total = S1 - corr;

    // higher exponents: p^{4a+1} with a>=1 (start at p^5)
    for (int p : primes_small) {
        if (p % 4 != 1) continue;
        u128 pow = 1;
        for (int i = 0; i < 5; ++i) pow *= (u64)p;
        if (pow > N) break;
        const u128 p4 = (u128)p * p * p * p;
        while (pow <= N) {
            const u64 T = isqrt_u64((u64)(N / (u64)pow));
            total += (u128)(T - T / (u64)p);
            if (pow > (u128)N / p4) break;
            pow *= p4;
        }
    }

    return (u64)total;
}

static u64 F(u64 N, const PrimeCountMod4& pc, const std::vector<int>& primes_small, const std::vector<int>& spf,
             const std::vector<uint8_t>& parity_odd1mod4) {
    (void)spf;
    const u64 a_even = count_A_even_v2(N, pc, primes_small);
    const u64 a_odd = count_A_even_v2(N / 2, pc, primes_small); // multiply-by-2 bijection
    return a_even + a_odd + count_B(N, parity_odd1mod4);
}

int main() {
    const u64 Nmax = 1000000000000ULL;
    PrimeCountMod4 pc(Nmax);

    const int LIM = 1000000;
    const std::vector<int> spf = sieve_spf(LIM);
    const std::vector<int> primes_small = sieve_primes_int(LIM);

    // parity[m] = 1 iff m has an odd number of primes ≡1 (mod 4) to odd exponent.
    std::vector<uint8_t> parity((size_t)LIM + 1, 0);
    parity[1] = 0;
    for (int x = 2; x <= LIM; ++x) {
        int n = x;
        uint8_t par = 0;
        while (n > 1) {
            const int p = spf[n];
            int e = 0;
            while (n % p == 0) {
                n /= p;
                e ^= 1;
            }
            if (e && (p % 4 == 1)) par ^= 1;
        }
        parity[x] = par;
    }

    // Statement validations.
    assert(F(5, pc, primes_small, spf, parity) == 1ULL);
    assert(F(100, pc, primes_small, spf, parity) == 27ULL);
    assert(F(1000, pc, primes_small, spf, parity) == 233ULL);
    assert(F(1000000ULL, pc, primes_small, spf, parity) == 112168ULL);

    std::cout << F(Nmax, pc, primes_small, spf, parity) << "\n";
    return 0;
}

Python

from __future__ import annotations

import re
import shutil
import subprocess
from pathlib import Path

ANSWER_RE = re.compile(r"answer\s*:\s*(.+)$", re.IGNORECASE)
EQUAL_RE = re.compile(r"=\s*(.+)$")


def parse_output(stdout: str) -> str:
    lines = [line.strip() for line in stdout.splitlines() if line.strip()]
    if not lines:
        return ""
    answers = []
    equals = []
    for line in lines:
        m1 = ANSWER_RE.search(line)
        if m1:
            answers.append(m1.group(1).strip())
        m2 = EQUAL_RE.search(line)
        if m2:
            equals.append(m2.group(1).strip())
    if answers:
        return answers[-1]
    if equals:
        return equals[-1]
    return lines[-1]


def should_skip_cpp_checkpoints(src: Path) -> bool:
    try:
        text = src.read_text(encoding="utf-8", errors="ignore")
    except OSError:
        return False
    return "--skip-checkpoints" in text


def run_cpp(binary: Path, src: Path, root: Path) -> str:
    cmd = [str(binary)]
    if should_skip_cpp_checkpoints(src):
        cmd.append("--skip-checkpoints")

    try:
        return subprocess.check_output(cmd, text=True, cwd=root)
    except subprocess.CalledProcessError:
        return subprocess.check_output(cmd, text=True, cwd=src.parent)


def solve() -> str:
    problem_id = __file__.split("Euler")[-1].split(".")[0]
    root = Path(__file__).resolve().parent.parent
    src = root / "solutionsCpp" / f"Euler{problem_id}.cpp"
    binary = root / "solutionsCpp" / f".euler{problem_id}_py_bridge"

    if not binary.exists() or src.stat().st_mtime > binary.stat().st_mtime:
        compiler = shutil.which("clang++") or shutil.which("g++")
        if not compiler:
            raise RuntimeError("No C++ compiler found (clang++/g++).")
        subprocess.check_call([compiler, "-std=c++17", "-O2", str(src), "-o", str(binary)])

    output = run_cpp(binary=binary, src=src, root=root)
    parsed = parse_output(output)
    if not parsed:
        raise RuntimeError(f"Euler{problem_id} bridge produced empty output.")
    return parsed


if __name__ == "__main__":
    print(solve())

Java

import java.util.ArrayList;
import java.util.List;

public class Euler611 {
    static long isqrt(long x) {
        long r = (long) Math.sqrt(x);
        while ((r + 1) * (r + 1) <= x)
            r++;
        while (r * r > x)
            r--;
        return r;
    }

    static int ilog2(long x) {
        if (x <= 0)
            return 0;
        return 63 - Long.numberOfLeadingZeros(x);
    }

    static List<Integer> sievePrimesInt(int n) {
        boolean[] isPrime = new boolean[n + 1];
        for (int i = 2; i <= n; i++)
            isPrime[i] = true;
        for (int p = 2; (long) p * p <= n; p++) {
            if (isPrime[p]) {
                for (int j = p * p; j <= n; j += p) {
                    isPrime[j] = false;
                }
            }
        }
        List<Integer> primes = new ArrayList<>();
        for (int i = 2; i <= n; i++) {
            if (isPrime[i])
                primes.add(i);
        }
        return primes;
    }

    static long chiInt(long x) {
        if ((x & 1) == 0)
            return 0;
        return (x & 3) == 1 ? 1 : -1;
    }

    static long sumChi1To(long m) {
        long c1 = (m + 3) / 4;
        long c3 = (m + 1) / 4;
        return c1 - c3;
    }

    static class PrimeCountMod4 {
        long n;
        long sq;
        List<Long> vals;
        long[] gPi;
        long[] gChi;
        int[] id1;
        int[] id2;
        List<Integer> primes;
        long[] prefChiPrime;

        PrimeCountMod4(long n) {
            this.n = n;
            this.sq = isqrt(n);
            this.primes = sievePrimesInt((int) sq);

            this.vals = new ArrayList<>();
            for (long l = 1; l <= n;) {
                long w = n / l;
                vals.add(w);
                l = n / w + 1;
            }

            int m = vals.size();
            gPi = new long[m];
            gChi = new long[m];
            id1 = new int[(int) sq + 1];
            id2 = new int[(int) sq + 1];

            for (int i = 0; i < m; i++) {
                long w = vals.get(i);
                gPi[i] = (w >= 2) ? (w - 1) : 0;
                gChi[i] = (w >= 1) ? (sumChi1To(w) - 1) : 0;
                if (w <= sq)
                    id1[(int) w] = i;
                else
                    id2[(int) (n / w)] = i;
            }

            prefChiPrime = new long[primes.size() + 1];
            for (int i = 0; i < primes.size(); i++) {
                prefChiPrime[i + 1] = prefChiPrime[i] + chiInt(primes.get(i));
            }

            for (int i = 0; i < primes.size(); i++) {
                long p = primes.get(i);
                long p2 = p * p;
                if (p2 > n)
                    break;
                long chiP = chiInt(p);

                for (int j = 0; j < m; j++) {
                    long w = vals.get(j);
                    if (w < p2)
                        break;
                    long q = w / p;
                    int idx = (q <= sq) ? id1[(int) q] : id2[(int) (n / q)];
                    gPi[j] -= gPi[idx] - i;
                    if (chiP != 0) {
                        gChi[j] -= chiP * (gChi[idx] - prefChiPrime[i]);
                    }
                }
            }
        }

        int id(long x) {
            return (x <= sq) ? id1[(int) x] : id2[(int) (n / x)];
        }

        long pi(long x) {
            return gPi[id(x)];
        }

        long sumChiPrimes(long x) {
            return gChi[id(x)];
        }

        long pi1(long x) {
            if (x < 5)
                return 0;
            long pix = pi(x);
            long oddPrimes = pix - 1;
            long s = sumChiPrimes(x);
            return (oddPrimes + s) / 2;
        }
    }

    static int[] sieveSpf(int n) {
        int[] spf = new int[n + 1];
        List<Integer> primes = new ArrayList<>();
        for (int i = 2; i <= n; i++) {
            if (spf[i] == 0) {
                spf[i] = i;
                primes.add(i);
            }
            for (int p : primes) {
                long v = (long) p * i;
                if (v > n)
                    break;
                spf[(int) v] = p;
                if (p == spf[i])
                    break;
            }
        }
        return spf;
    }

    static long countB(long N, byte[] parityOdd1Mod4) {
        long lim = isqrt(N);
        long ans = 0;
        for (long m = 1; m <= lim; m += 2) {
            if (parityOdd1Mod4[(int) m] == 0)
                continue;
            long base = m * m;
            long t = N / base;
            ans += ilog2(t) + 1;
        }
        return ans;
    }

    static long countAEvenV2(long N, PrimeCountMod4 pc, List<Integer> primesSmall) {
        long S1 = 0;
        long tmax = isqrt(N);
        for (long t = 1; t <= tmax; t++) {
            long R = N / (t * t);
            if (R < 5)
                break;
            long L = N / ((t + 1) * (t + 1));
            long cnt = pc.pi1(R) - pc.pi1(L);
            S1 += t * cnt;
        }

        long corr = 0;
        long cbrtN = 10000;
        for (int p : primesSmall) {
            if (p > cbrtN)
                break;
            if (p % 4 != 1)
                continue;
            long T = isqrt(N / p);
            corr += T / p;
        }

        long total = S1 - corr;

        for (int p : primesSmall) {
            if (p % 4 != 1)
                continue;
            long powVal = (long) p * p * p * p * p;
            if (powVal > N || powVal < 0)
                break;
            long p4 = (long) p * p * p * p;
            while (powVal <= N && powVal > 0) {
                long T = isqrt(N / powVal);
                total += T - T / p;
                if (powVal > N / p4)
                    break;
                powVal *= p4;
            }
        }
        return total;
    }

    static long F(long N, PrimeCountMod4 pc, List<Integer> primesSmall, int[] spf, byte[] parity) {
        long aEven = countAEvenV2(N, pc, primesSmall);
        long aOdd = countAEvenV2(N / 2, pc, primesSmall);
        return aEven + aOdd + countB(N, parity);
    }

    public static String solve() {
        long Nmax = 1000000000000L;
        PrimeCountMod4 pc = new PrimeCountMod4(Nmax);

        int LIM = 1000000;
        int[] spf = sieveSpf(LIM);
        List<Integer> primesSmall = sievePrimesInt(LIM);

        byte[] parity = new byte[LIM + 1];
        for (int x = 2; x <= LIM; x++) {
            int n = x;
            byte par = 0;
            while (n > 1) {
                int p = spf[n];
                int e = 0;
                while (n % p == 0) {
                    n /= p;
                    e ^= 1;
                }
                if (e != 0 && (p % 4 == 1)) {
                    par ^= 1;
                }
            }
            parity[x] = par;
        }

        long ans = F(Nmax, pc, primesSmall, spf, parity);
        return Long.toString(ans);
    }

    public static void main(String[] args) {
        System.out.println(solve());
    }
}