All Euler problems
Project Euler

Semiprimes

A composite number is called a semiprime if it is the product of exactly two prime factors (not necessarily distinct). The first few semiprimes are: 4, 6, 9, 10, 14, 15, 21, 22,... How many composi...

Source sync Apr 19, 2026
Problem #0187
Level Level 04
Solved By 12,434
Languages C++, Python
Answer 17427258
Length 275 words
number_theorylinear_algebrasearch

Problem Statement

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

A composite is a number containing at least two prime factors. For example, \(15 = 3 \times 5\); \(9 = 3 \times 3\); \(12 = 2 \times 2 \times 3\).

There are ten composites below thirty containing precisely two, not necessarily distinct, prime factors: \(4, 6, 9, 10, 14, 15, 21, 22, 25, 26\).

How many composite integers, \(n \lt 10^8\), have precisely two, not necessarily distinct, prime factors?

Problem 187: Semiprimes

Mathematical Analysis

Definition

A semiprime nn can be written as n=pqn = p \cdot q where pqp \le q are both prime. The condition n<108n < 10^8 means pq<108p \cdot q < 10^8.

Counting Strategy

For each prime pp, we count the number of primes qpq \ge p such that pq<108p \cdot q < 10^8, i.e., q<108/pq < 10^8 / p.

Since pqp \le q, we need p2<108p^2 < 10^8, so p<104=10000p < 10^4 = 10000. Actually, p1081=9999p \le \lfloor\sqrt{10^8 - 1}\rfloor = 9999, so pp ranges over all primes up to 9999.

For each such prime pp, the number of valid primes qq is:

π(1081p)π(p1)\pi\left(\left\lfloor\frac{10^8 - 1}{p}\right\rfloor\right) - \pi(p - 1)

where π(x)\pi(x) is the prime counting function.

Editorial

Count composite integers n < 10^8 with exactly two prime factors. We use the Sieve of Eratosthenes to find all primes up to 108/2=5×10710^8 / 2 = 5 \times 10^7 (since the smallest prime is 2). We then compute a prefix sum array for the prime counting function. Finally, iterate over each prime p9999p \le 9999, add π((1081)/p)π(p1)\pi(\lfloor(10^8 - 1)/p\rfloor) - \pi(p - 1) to the answer.

Pseudocode

Use the Sieve of Eratosthenes to find all primes up to $10^8 / 2 = 5 \times 10^7$ (since the smallest prime is 2)
Compute a prefix sum array for the prime counting function
For each prime $p \le 9999$, add $\pi(\lfloor(10^8 - 1)/p\rfloor) - \pi(p - 1)$ to the answer

Proof of Correctness

Every semiprime n=pqn = p \cdot q with pqp \le q is counted exactly once: when we process the smaller prime factor pp. Since we require qpq \ge p, there is no double-counting.

Correctness

Theorem. The method described above computes exactly the quantity requested in the problem statement.

Proof. The preceding analysis identifies the admissible objects and derives the formula, recurrence, or exhaustive search carried out by the algorithm. The computation evaluates exactly that specification, so every valid contribution is included once and no invalid contribution is counted. Therefore the returned value is the required answer. \square

Complexity

  • Time: O(NloglogN)O(N \log \log N) for the sieve where N=5×107N = 5 \times 10^7, plus O(N)O(\sqrt{N}) for the summation.
  • Space: O(N)O(N) for the sieve and prefix sums.

Answer

17427258\boxed{17427258}

Code

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

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

int main() {
    const int LIMIT = 100000000;
    const int SIEVE_SIZE = LIMIT / 2; // max q when p=2

    // Sieve of Eratosthenes
    vector<bool> is_composite(SIEVE_SIZE, false);
    vector<int> primes;

    for (int i = 2; i < SIEVE_SIZE; i++) {
        if (!is_composite[i]) {
            primes.push_back(i);
            if ((long long)i * i < SIEVE_SIZE) {
                for (long long j = (long long)i * i; j < SIEVE_SIZE; j += i) {
                    is_composite[j] = true;
                }
            }
        }
    }

    // For each prime p, count primes q >= p with p*q < LIMIT
    long long count = 0;
    int n = primes.size();

    for (int i = 0; i < n; i++) {
        long long p = primes[i];
        if (p * p >= LIMIT) break;

        // Find largest index j such that primes[j] < LIMIT / p
        // and primes[j] >= p
        long long max_q = (LIMIT - 1) / p;

        // Binary search for max_q in primes
        int lo = i, hi = n - 1, best = i - 1;
        while (lo <= hi) {
            int mid = (lo + hi) / 2;
            if (primes[mid] <= max_q) {
                best = mid;
                lo = mid + 1;
            } else {
                hi = mid - 1;
            }
        }

        if (best >= i) {
            count += (best - i + 1);
        }
    }

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