Prime Subset Sums
Let S = {2, 3, 5, 7, 11, ldots} be the set of all primes less than 5000. Find the number of subsets of S whose elements sum to a prime number. Give the last 16 digits (i.e., the answer modulo 10^16).
Problem Statement
This archive keeps the full statement, math, and original media on the page.
Let \(S = \{2, 3, 5, \dots , 4999\}\) be the set of prime numbers less than \(5000\).
Find the number of subsets of \(S\), the sum of whose elements is a prime number.
Enter the rightmost \(16\) digits as your answer.
Problem 249: Prime Subset Sums
Mathematical Foundation
Theorem 1 (Subset-sum counting via 0/1 knapsack DP). Let be the primes less than (where ), and let . Define as the number of subsets of that sum to exactly , reduced modulo . Then the standard 0/1 knapsack recurrence correctly computes for all .
Proof. We prove by induction on that after processing primes , equals (mod ) the number of subsets of summing to .
Base case (): (empty subset), for . Correct.
Inductive step: Assume the claim holds after primes. When processing , for from down to , we update . The reverse iteration ensures that the value used is from the -th stage (before was available). Thus:
- after update (subsets of summing to ) (subsets of summing to ). The first term counts subsets not containing ; the second counts subsets containing (since adding to a subset summing to gives a subset summing to ). Together, these are exactly the subsets of summing to .
Lemma 1 (Prime sieve correctness). The Sieve of Eratosthenes correctly identifies all primes up to in time.
Proof. Classical result. Each composite has a prime factor , so it is marked during the sieve of . No prime is ever marked.
Theorem 2 (Final summation). The answer is
Proof. Each subset with prime sum contributes exactly 1 to for exactly one prime . Summing over prime counts each qualifying subset once.
Editorial
We collect primes below 5000. We then 0/1 Knapsack DP. Finally, sum over prime target sums. We use dynamic programming over the state space implied by the derivation, apply each admissible transition, and read the answer from the final table entry.
Pseudocode
Sieve primes up to sigma = 1,548,136
Collect primes below 5000
|primes_5000| = 669
0/1 Knapsack DP
Sum over prime target sums
Complexity Analysis
- Time: The DP performs additions modulo . The sieve takes . The final summation is . Total: .
- Space: for the DP array and sieve, approximately 12 MB for 64-bit entries.
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#include <bits/stdc++.h>
using namespace std;
int main() {
const unsigned long long MOD = 10000000000000000ULL; // 10^16
// Generate all primes below 5000
const int LIMIT = 5000;
vector<bool> sieve(LIMIT, true);
sieve[0] = sieve[1] = false;
for (int i = 2; i * i < LIMIT; i++)
if (sieve[i])
for (int j = i * i; j < LIMIT; j += i)
sieve[j] = false;
vector<int> primes;
for (int i = 2; i < LIMIT; i++)
if (sieve[i]) primes.push_back(i);
long long S = 0;
for (int p : primes) S += p;
// Sieve up to S for final primality check
vector<bool> is_prime(S + 1, true);
is_prime[0] = is_prime[1] = false;
for (long long i = 2; i * i <= S; i++)
if (is_prime[i])
for (long long j = i * i; j <= S; j += i)
is_prime[j] = false;
// DP: 0/1 knapsack
vector<unsigned long long> dp(S + 1, 0);
dp[0] = 1;
for (int p : primes) {
for (long long s = S; s >= p; s--) {
dp[s] += dp[s - p];
if (dp[s] >= MOD) dp[s] -= MOD;
}
}
unsigned long long answer = 0;
for (long long s = 2; s <= S; s++) {
if (is_prime[s]) {
answer += dp[s];
if (answer >= MOD) answer -= MOD;
}
}
cout << answer << endl;
return 0;
}
def solve():
"""
Problem 249: Prime Subset Sums
Count subsets of primes below 5000 whose sum is prime, mod 10^16.
"""
MOD = 10**16
LIMIT = 5000
# Sieve to get all primes below 5000
is_prime_sieve = [True] * LIMIT
is_prime_sieve[0] = is_prime_sieve[1] = False
for i in range(2, int(LIMIT**0.5) + 1):
if is_prime_sieve[i]:
for j in range(i*i, LIMIT, i):
is_prime_sieve[j] = False
primes = [i for i in range(2, LIMIT) if is_prime_sieve[i]]
S = sum(primes)
# Sieve up to S
is_prime = bytearray(S + 1)
for i in range(2, S + 1):
is_prime[i] = 1
for i in range(2, int(S**0.5) + 1):
if is_prime[i]:
for j in range(i*i, S + 1, i):
is_prime[j] = 0
# DP (0/1 knapsack)
dp = [0] * (S + 1)
dp[0] = 1
for p in primes:
for s in range(S, p - 1, -1):
dp[s] = (dp[s] + dp[s - p]) % MOD
answer = 0
for s in range(2, S + 1):
if is_prime[s]:
answer = (answer + dp[s]) % MOD
print(answer)
solve()