All Euler problems
Project Euler

Prime Constellation Counting

A twin prime pair is (p, p+2) where both p and p+2 are prime. Find the number of twin prime pairs with p < 10^7.

Source sync Apr 19, 2026
Problem #0910
Level Level 39
Solved By 103
Languages C++, Python
Answer 547480666
Length 421 words
number_theorymodular_arithmeticbrute_force

Problem Statement

This archive keeps the full statement, math, and original media on the page.

An L-expression is defined as any one of the following:

  • a natural number;

  • the symbol $A$;

  • the symbol $Z$;

  • the symbol $S$;

  • a pair of L-expressions $u, v$, which is written as $u(v)$.

An L-expression can be transformed according to the following rules:

  • $A(x) \to x + 1$ for any natural number $x$;

  • $Z(u)(v) \to v$ for any L-expressions $u, v$;

  • $S(u)(v)(w) \to v(u(v)(w))$ for any L-expressions $u, v, w$.

For example, after applying all possible rules, the L-expression $S(Z)(A)(0)$ is transformed to the number $1$: $$S(Z)(A)(0) \to A(Z(A)(0)) \to A(0) \to 1.$$ Similarly, the L-expression $S(S)(S(S))(S(Z))(A)(0)$ is transformed to the number $6$ after applying all possible rules.

Define the following L-expressions:

  • $C_0 = Z$;

  • $C_i = S(C_{i - 1})$ for $i \ge 1$;

  • $D_i = C_i(S)(S)$.

For natural numbers $a, b, c, d, e$, let $F(a, b, c, d, e)$ denote the result of the L-expression $D_a(D_b)(D_c)(C_d)(A)(e)$ after applying all possible rules.

Find the last nine digits of $F(12, 345678, 9012345, 678, 90)$.

Note: it can be proved that the L-expression in question can only be transformed a finite number of times, and the final result does not depend on the order of the transformations.

Problem 910: Prime Constellation Counting

Mathematical Analysis

Twin Primes and the Sieve

Twin primes are pairs of primes differing by 2. The first few: (3,5),(5,7),(11,13),(17,19),(29,31),(41,43),(3,5), (5,7), (11,13), (17,19), (29,31), (41,43), \ldots

Observation. For p5p \ge 5, if (p,p+2)(p, p+2) are both prime, then p5(mod6)p \equiv 5 \pmod{6} (since one of p,p+1,p+2p, p+1, p+2 must be divisible by 3, and it cannot be pp or p+2p+2, so p+10(mod3)p+1 \equiv 0 \pmod{3}, giving p2(mod3)p \equiv 2 \pmod{3}, combined with pp odd gives p5(mod6)p \equiv 5 \pmod{6}).

The Twin Prime Conjecture

Conjecture (Twin Prime). There are infinitely many twin prime pairs.

This is one of the oldest unsolved problems in number theory. The best known result is Zhang’s 2013 breakthrough (later refined by Maynard and the Polymath project): there exist infinitely many pairs of primes differing by at most 246.

Hardy-Littlewood Conjecture

Conjecture (Hardy-Littlewood First). The number of twin prime pairs (p,p+2)(p, p+2) with pNp \le N satisfies:

π2(N)2C2N(lnN)2(1)\pi_2(N) \sim 2C_2 \frac{N}{(\ln N)^2} \tag{1}

where C2=p3p(p2)(p1)2=0.6601618C_2 = \prod_{p \ge 3} \frac{p(p-2)}{(p-1)^2} = 0.6601618\ldots is the twin prime constant.

The product converges because the terms are 11/(p1)2=1O(1/p2)1 - 1/(p-1)^2 = 1 - O(1/p^2).

Brun’s Theorem

Theorem (Brun, 1919). The sum of reciprocals of all twin primes converges:

B=(p,p+2) twin(1p+1p+2)=1.902160583B = \sum_{(p,p+2) \text{ twin}} \left(\frac{1}{p} + \frac{1}{p+2}\right) = 1.902160583\ldots

This is Brun’s constant. In contrast, p prime1/p=\sum_{p \text{ prime}} 1/p = \infty (Euler).

The Sieve of Eratosthenes

The standard algorithm for finding all primes up to NN:

  1. Create boolean array sieve[0..N]\text{sieve}[0..N], initialized to true.
  2. Set sieve[0]=sieve[1]=false\text{sieve}[0] = \text{sieve}[1] = \text{false}.
  3. For i=2,3,,Ni = 2, 3, \ldots, \lfloor\sqrt{N}\rfloor: if sieve[i]\text{sieve}[i] is true, mark all multiples i2,i2+i,i^2, i^2+i, \ldots as composite.

Theorem. The sieve correctly identifies all primes N\le N.

Proof. Every composite nNn \le N has a prime factor pNp \le \sqrt{N}, so nn is marked composite when processing pp. \square

Counting Twin Primes

After sieving, scan pairs (p,p+2)(p, p+2) for p=2,3,,N2p = 2, 3, \ldots, N-2. The only even twin pair is (2,4)(2, 4), but 4 is not prime. So all twin pairs have pp odd, p+2p+2 odd, and we only check odd pp.

Concrete Values

NNπ2(N)\pi_2(N)2C2N/(lnN)22C_2 N/(\ln N)^2Ratio
10310^33527.71.26
10410^42051661.24
10510^5122410751.14
10610^6816974071.10
10710^758980537891.10

The Hardy-Littlewood prediction improves with NN but overestimates the convergence rate.

Prime Gaps and Twin Primes

The prime gap gn=pn+1png_n = p_{n+1} - p_n equals 2 exactly for twin primes (plus (2,3)(2,3) where g=1g=1). The average gap near NN is lnN\ln N. Twin primes represent the minimum possible gap for p>3p > 3.

Editorial

Count twin prime pairs (p, p+2) with p < 10^7. We sieve of Eratosthenes up to N+2N + 2 (to check p+2p + 2 for the largest pp).

Pseudocode

Sieve of Eratosthenes up to $N + 2$ (to check $p + 2$ for the largest $p$)
Count pairs where both $\text{sieve}[p]$ and $\text{sieve}[p+2]$ are true

Proof of Correctness

Theorem. The algorithm correctly counts all twin prime pairs (p,p+2)(p, p+2) with pNp \le N.

Proof. The sieve identifies all primes N+2\le N + 2 without error. For each pNp \le N, checking sieve[p]sieve[p+2]\text{sieve}[p] \land \text{sieve}[p+2] is necessary and sufficient for (p,p+2)(p, p+2) to be a twin pair. \square

Complexity Analysis

  • Sieve: O(NloglogN)O(N \log \log N) time, O(N)O(N) space.
  • Counting: O(N)O(N) single pass.
  • Segmented sieve variant: O(N)O(N) time, O(N)O(\sqrt{N}) space.

For N=107N = 10^7: the sieve takes about 0.1 seconds in C++.

Answer

547480666\boxed{547480666}

Code

Each problem page includes the exact C++ and Python source files from the local archive.

C++ project_euler/problem_910/solution.cpp
#include <bits/stdc++.h>
using namespace std;

/*
 * Problem 910: Prime Constellation Counting
 *
 * Count twin prime pairs (p, p+2) with p < 10^7.
 *
 * Method: Sieve of Eratosthenes + linear scan.
 *
 * Hardy-Littlewood conjecture: pi_2(N) ~ 2*C_2 * N / (ln N)^2
 * where C_2 = prod_{p>=3} p(p-2)/(p-1)^2 ≈ 0.6602.
 *
 * Brun's theorem: sum of 1/p over twin primes converges (B ≈ 1.9022).
 */

int main() {
    const int N = 10000000;

    // Sieve of Eratosthenes
    vector<bool> sieve(N + 3, true);
    sieve[0] = sieve[1] = false;
    for (int i = 2; (long long)i * i <= N + 2; i++) {
        if (sieve[i]) {
            for (int j = i * i; j <= N + 2; j += i) {
                sieve[j] = false;
            }
        }
    }

    // Count twin prime pairs
    int count = 0;
    for (int p = 2; p <= N; p++) {
        if (sieve[p] && sieve[p + 2]) {
            count++;
        }
    }

    // Verify small known values
    // Twin primes below 100: (3,5),(5,7),(11,13),(17,19),(29,31),(41,43),(59,61),(71,73) = 8
    int small_count = 0;
    for (int p = 2; p <= 100; p++)
        if (sieve[p] && sieve[p + 2])
            small_count++;
    assert(small_count == 8);

    // Below 1000: 35 pairs
    int med_count = 0;
    for (int p = 2; p <= 1000; p++)
        if (sieve[p] && sieve[p + 2])
            med_count++;
    assert(med_count == 35);

    cout << count << endl;
    return 0;
}