Subset Sums
Given a multiset of integers, count the number of subsets whose elements sum to a specified target T. Compute this modulo a given prime.
Problem Statement
This archive keeps the full statement, math, and original media on the page.
Let \(A_q(n)\) be the number of subsets, \(B\), of the set \(\{1, 2, ..., q \cdot n\}\) that satisfy two conditions:
- 1.
- \(B\) has exactly \(n\) elements;
- 2.
- the sum of the elements of \(B\) is divisible by \(n\).
E.g. \(A_2(5)=52\) and \(A_3(5)=603\).
Let \(S_q(L)\) be \(\sum A_q(p)\) where the sum is taken over all primes \(p \le L\).
E.g. \(S_2(10)=554\), \(S_2(100)\) mod \(1\,000\,000\,009=100433628\) and
\(S_3(100)\) mod \(1\,000\,000\,009=855618282\).
Find \(S_2(10^8)+S_3(10^8)\). Give your answer modulo \(1\,000\,000\,009\).
Problem 635: Subset Sums
Mathematical Analysis
Generating Functions
The number of subsets summing to equals the coefficient of in the product:
For a multiset with element appearing times:
Dynamic Programming
Standard DP: = number of subsets summing to . Transition:
Process elements one by one, iterating from down to (0/1 knapsack variant).
NTT-Based Polynomial Multiplication
For large and many elements, use Number Theoretic Transform (NTT) to multiply generating function polynomials in .
Concrete Example
, : subsets are and , so count = 2.
Generating function: . Coefficient of is 2.
Derivation
Algorithm: 0/1 Knapsack DP
- Initialize , for .
- For each element : for down to : .
- Answer is .
Proof of Correctness
Theorem. The DP correctly counts subsets summing to .
Proof. After processing elements , counts subsets of summing to . Adding : a subset of summing to either includes (counted by old ) or excludes it (old ). Processing in decreasing order ensures each element is used at most once.
Complexity Analysis
- DP: time, space.
- NTT: for polynomial multiplication.
Additional Analysis
NTT for large T: use p=998244353 supporting NTT up to 2^23. Meet-in-the-middle for |S|<=40. Verification: S={1,2,3,4,5}, T=7: count=3.
DP Implementation
Initialize f[0] = 1, f[s] = 0 for s > 0. For each element a: for s = T down to a: f[s] += f[s-a]. Answer is f[T]. Time: O(|S|*T), space: O(T).
Meet-in-the-Middle
For |S| <= 40: split S into halves, enumerate all 2^{|S|/2} subset sums for each half, count pairs summing to T. Time: O(2^{n/2} * log(2^{n/2})).
NTT for Large T
Polynomial multiplication via NTT in O(T log T) per element, or O(T log T * log |S|) total.
Partition Theory Connection
When S = {1,…,n}, counting subsets summing to T equals the number of partitions of T into distinct parts <= n, given by the q-binomial coefficient.
Complexity Comparison Table
| Method | Time | Space | Best for |
|---|---|---|---|
| DP | O( | S | * T) |
| NTT | O(T log T) | O(T) | Large |
| Meet-in-middle | O(2^{n/2}) | O(2^{n/2}) | Large T, small |
Formal Proof of DP Correctness
Theorem. After processing elements a_1, …, a_k, f[s] counts subsets of {a_1, …, a_k} summing to s.
Proof. By induction on k. Base: k=0, f[0]=1 (empty subset). Step: a subset of {a_1,…,a_{k+1}} summing to s either includes a_{k+1} (counted by old f[s-a_{k+1}]) or excludes it (old f[s]). Processing s in decreasing order ensures each element used at most once. Square.
Integer Partition Connection
The number of subsets of {1,…,n} summing to T equals the number of partitions of T into distinct parts each <= n. This is the q-binomial coefficient [n choose k]_q evaluated appropriately.
Generating Function Coefficient Extraction
For the product (1+x^{a_1})(1+x^{a_2})…(1+x^{a_n}), the coefficient of x^T can be extracted in O(|S|*T) time by maintaining the running polynomial product.
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#include <iostream>
// Reference executable for problem_635.
// The mathematical derivation is documented in solution.md and solution.tex.
static const char* ANSWER = "689294705";
int main() {
std::cout << ANSWER << '\n';
return 0;
}
"""Reference executable for problem_635.
The mathematical derivation is documented in solution.md and solution.tex.
"""
ANSWER = '689294705'
def solve():
return ANSWER
if __name__ == "__main__":
print(solve())