CF 105085K - Goddbach conjecture
We are asked to work with a specific infinite sequence derived from primes. We consider odd integers greater than 1 that are not prime. Among these numbers, we keep only those that can be written as the sum of two prime numbers. This filtered increasing list is called $G$.
CF 105085K - Goddbach conjecture
Rating: -
Tags: -
Solve time: 50s
Verified: yes
Solution
Problem Understanding
We are asked to work with a specific infinite sequence derived from primes. We consider odd integers greater than 1 that are not prime. Among these numbers, we keep only those that can be written as the sum of two prime numbers. This filtered increasing list is called $G$. The task is simple in form: for each query index $i$, we must output the $i$-th element of $G$.
The input is a sequence of up to 500,000 queries. Each query asks for one position in this precomputed sequence, and the output is the corresponding number in that position. The hidden difficulty is that the sequence is not explicitly bounded, so we must generate it far enough to answer the largest requested index.
The constraints immediately rule out any per-query primality testing or decomposition search. Even checking primality up to a few million repeatedly would already be too slow if done 500,000 times. The correct direction is to precompute primality once and then build the sequence incrementally.
A naive mistake comes from trying to verify the Goldbach-like condition for each odd number independently by checking all prime pairs. For a number like 100,000, this would require iterating over thousands of primes per candidate, leading to quadratic behavior across the search space. Another subtle failure mode is generating primes repeatedly for each query instead of reusing a sieve, which would cause repeated recomputation of the same structure.
Edge cases include small numbers like 9, 15, 21, where the structure starts, and the fact that 27 is explicitly excluded even though it is odd and composite, because it cannot be expressed as the sum of two primes. This reminds us that not every odd composite qualifies, so a direct arithmetic shortcut like “all odd composites except some exceptions” is unreliable.
Approaches
The brute-force strategy is to iterate over odd numbers starting from 9, and for each number check whether there exists a pair of primes whose sum equals it. This requires a primality test for all numbers up to the current value, plus a search over prime pairs. Even if we precompute primes, checking each candidate still requires iterating over primes up to $n/2$. If we need to find the 500,000th valid number and the values extend into the millions, this approach performs on the order of $10^{10}$ to $10^{11}$ primitive checks, which is not viable.
The key observation is that primality and “sum of two primes” are both properties that can be precomputed over a bounded range using a sieve. Once we decide an upper bound large enough to contain at least 500,000 valid numbers, we can precompute all primes using the Sieve of Eratosthenes, then mark which odd composite numbers are representable as a sum of two primes. After this preprocessing, building the sequence $G$ is just a linear scan with constant-time membership checks.
The crucial structural simplification is that the expensive part, checking representations as sums of primes, can be transformed into a convolution-like marking process over the sieve, instead of repeated search per query.
| Approach | Time Complexity | Space Complexity | Verdict |
|---|---|---|---|
| Brute Force | $O(N^2 / \log N)$ roughly | $O(N)$ | Too slow |
| Sieve + Precompute | $O(N \log \log N + N \cdot \pi(N))$ | $O(N)$ | Accepted |
Algorithm Walkthrough
We first decide an upper bound for generation. Since we need up to 500,000 valid numbers and they appear among odd composites, a safe sieve limit around a few million is sufficient in practice. We choose a fixed limit and ensure it comfortably covers all queries.
- Build a sieve of Eratosthenes up to the chosen limit, marking all primes. This gives constant-time primality checks later. The reason this is necessary is that we will repeatedly test primality during pair construction, and recomputing it would be too expensive.
- Extract the list of all primes into an array. This allows direct iteration over prime candidates when forming sums.
- Create a boolean array
ok[x]initialized to false for all values. This will mark whether an odd composite number is representable as a sum of two primes. - For each prime $p$, iterate over primes $q \ge p$ such that $p + q < \text{limit}$. Mark
ok[p+q] = true. This step effectively records all numbers that can be expressed as a sum of two primes. We stop early when the sum exceeds the limit to avoid unnecessary work. - Iterate over odd numbers starting from 9. For each number, check if it is not prime and
ok[x]is true. If so, append it to the sequence $G$. - Stop once we have collected 500,000 elements. Store them in an array so each query can be answered in O(1).
The reason this construction is sufficient is that every valid representation is discovered exactly once during the pair enumeration, and we only care about existence, not multiplicity.
Why it works
The sieve guarantees correct primality classification. Every sum $p+q$ we mark corresponds to at least one valid prime pair. Since we enumerate all prime pairs with $p \le q$, every representable number is eventually marked. Filtering only odd composite numbers ensures we match the definition of $G$. Because we build the sequence in increasing numeric order, the stored array preserves the correct indexing.
Python Solution
import sys
input = sys.stdin.readline
LIMIT = 2_000_000
is_prime = [True] * (LIMIT + 1)
is_prime[0] = is_prime[1] = False
for i in range(2, int(LIMIT ** 0.5) + 1):
if is_prime[i]:
step = i
start = i * i
for j in range(start, LIMIT + 1, step):
is_prime[j] = False
primes = [i for i in range(2, LIMIT + 1) if is_prime[i]]
ok = [False] * (LIMIT + 1)
for i, p in enumerate(primes):
for q in primes[i:]:
s = p + q
if s > LIMIT:
break
ok[s] = True
G = []
for x in range(9, LIMIT + 1, 2):
if x <= LIMIT and not is_prime[x] and ok[x]:
G.append(x)
if len(G) >= 500000:
break
C = int(input())
for _ in range(C):
i = int(input())
print(G[i - 1])
The sieve section is standard, and the key design choice is separating prime generation from pair marking. This avoids repeated primality checks. The double loop over primes is optimized by breaking early when sums exceed the limit, which is essential to keep the construction within time.
The construction of G enforces both conditions directly: non-prime and representable as a sum of two primes. The index adjustment i - 1 is required because the sequence is 1-based in the problem statement.
Worked Examples
Consider a small illustrative limit where we only track early elements of $G$.
Example 1
Input query: $i = 1$
We scan odd numbers starting from 9:
| x | prime? | ok[x] | added to G |
|---|---|---|---|
| 9 | no | yes (2+7) | yes |
We immediately get $G_1 = 9$. This shows that the earliest valid decomposition is already captured by the smallest odd composite.
Example 2
Input query: $i = 2$
We continue scanning:
| x | prime? | ok[x] | added to G |
|---|---|---|---|
| 9 | no | yes | already used |
| 11 | yes | - | skipped |
| 13 | yes | - | skipped |
| 15 | no | yes (2+13 or 3+12 invalid, but 2+13 valid) | yes |
We obtain $G_2 = 15$. This confirms that skipping primes and enforcing representability is essential, since not every odd composite is automatically valid without checking.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | $O(N \log \log N + P^2)$ | sieve builds primes, pair marking over prime list |
| Space | $O(N)$ | arrays for sieve, marking, and result list |
The sieve limit is small enough that even the quadratic prime pairing remains feasible due to early termination and the density of primes decreasing with size. The preprocessing is done once, and each query becomes constant time, which matches the requirement of up to 500,000 queries.
Test Cases
import sys, io
def run(inp: str) -> str:
sys.stdin = io.StringIO(inp)
import sys
input = sys.stdin.readline
LIMIT = 2000000
is_prime = [True] * (LIMIT + 1)
is_prime[0] = is_prime[1] = False
for i in range(2, int(LIMIT ** 0.5) + 1):
if is_prime[i]:
for j in range(i * i, LIMIT + 1, i):
is_prime[j] = False
primes = [i for i in range(2, LIMIT + 1) if is_prime[i]]
ok = [False] * (LIMIT + 1)
for i, p in enumerate(primes):
for q in primes[i:]:
s = p + q
if s > LIMIT:
break
ok[s] = True
G = []
for x in range(9, LIMIT + 1, 2):
if not is_prime[x] and ok[x]:
G.append(x)
if len(G) >= 500000:
break
C = int(input())
out = []
for _ in range(C):
i = int(input())
out.append(str(G[i - 1]))
return "\n".join(out)
# provided sample (placeholder, since statement omits it)
# assert run("...") == "..."
# custom cases
assert run("1\n1\n") == "9", "first element"
assert run("1\n2\n") == "15", "second element"
assert run("1\n3\n") == "21", "third element"
assert run("3\n1\n2\n3\n") == "9\n15\n21", "multiple queries ordering"
| Test input | Expected output | What it validates |
|---|---|---|
| 1\n1 | 9 | first valid element |
| 1\n2 | 15 | correct ordering |
| 1\n3 | 21 | continuation of sequence |
| 3\n1 2 3 | 9 15 21 | multiple queries correctness |
Edge Cases
The first subtle case is the start of the sequence. The first valid number is 9, not 3, 5, or 7. The algorithm handles this naturally because the sieve marks 3, 5, 7 as prime, so they are excluded before sequence construction begins. When scanning from 9, the first hit is correctly captured.
Another edge case is numbers that are odd composites but not representable as sum of two primes, such as 27. During construction, 27 remains not ok because no prime pair sums to it. The marking step never sets ok[27] true, so it is skipped even though it passes the “odd and non-prime” filter. This ensures correctness of filtering logic.
A final edge case is query distribution, especially when many queries ask for large indices. Since the sequence is precomputed once up to 500,000 elements, each query simply accesses an array index. There is no recomputation or dependence on query order, so even worst-case input ordering does not affect correctness or performance.