Sum over Subsets DP
Authors: Rameez Parwez, Siyong Huang, Aakash Gokhale
Taking bitmask DP to the next level.
Prerequisites
Resources | ||||
---|---|---|---|---|
CF | Good explanation + problem list | |||
GFG | Goes over brute force solutions | |||
CF | Characterizing SOS DP as multidimensional prefix sums |
Sum Over Subsets (SOS) is technique used to efficiently calculate the sum of values for all subsets of a given set or bitmask. Instead of manually generating every subset, which can be slow, SOS uses bitwise operations to quickly go through only the necessary subsets.
The main trick is that for any bitmask , we can directly loop through all its subsets using:
This ensures we efficiently handle only the subsets of , skipping unnecessary combinations.
Implementation
Consider an array of elements. For a bitmask , we define as the sum of over all subset mask . That is:
The goal is to compute for all .
Solution
Brute Force
The naive solution is to iterate over all pair of masks, summing only when one of them is a subset of the other (i.e.,).
C++
vector<int> sos(1 << n);for (int x = 0; x < (1 << n); x++) {// iterate over all other sets and checks whether they're a subset of xfor (int i = 0; i < (1 << n); i++) {if ((i & x) == i) {sos[x] += a[i];}}}
Python
sos = [0] * (1 << n)for x in range(1 << n):# iterate over all other sets and checks whether they're a subset of xfor i in range(1 << n):if (x &i) == i:sos[x] += a[i]
This solution has a time complexity of , which is impractical for large .
Optimized Solution
Instead of iterating over all bitmasks for , we can optimize by iterating only over the subset mask of .
C++
vector<int> sos(1 << n);for (int x = 0; x < (1 << n); x++) {sos[x] = a[0];// iterate over all subsets of x directlyfor (int i = x; i > 0; i = (i - 1) & x) {sos[x] += a[i];}}
Python
sos = [0] * (1 << n)for x in range(1 << n):sos[x] = a[0]i = x# iterate over all subsets of x directlywhile i > 0:sos[x] += a[i]i = (i - 1) & x
How does this works?
Time Complexity:
Proof
Faster Solution using Dynamic Programming
The above solution still has redundancy. For example, if a bitmask has unset bits, then is summed times. If we precompute and reuse these sums, we can eliminate repeated additions.
Subset Mask Partitioning with
We define the subset as follows:
In simpler terms, contains all subset masks of whose bits to the left of the -th bit match those of .
For example:
The subsets can be recursively partitioned as follows:
- If the -th bit of is , then .
- If the -th bit of is :
- Subsets with the -th bit .
- Subsets with the -th bit .
Thus:
Using the above partitioning, we define a DP table where:
Time Complexity:
C++
vector<int> sos(1 << n);vector<vector<int>> dp(1 << n, vector<int> (n));for (int x = 0; x < (1 << n); x++) {dp[x][0] = a[x];if (x & 1) {dp[x][0] += a[x ^ 1];}for (int i = 1; i < n; i++) {dp[x][i] = dp[x][i - 1];
Python
sos = [0] * (1 << n)dp = [[0] * n for _ in range(1 << n)]for x in range(1 << n):dp[x][0] = a[x]if x & 1:dp[x][0] += a[x ^ 1]for i in range(1, n):dp[x][i] = dp[x][i - 1]if x & (1 << i):dp[x][i] += dp[x ^ (1 << i)][i - 1]sos[x] = dp[x][n - 1]
Optimized Memory Usage
Since only depends on , we can reuse the DP array.
C++
for (int i = 0; i < (1 << n); i++) {sos[i] = a[i];}for (int i = 0; i < n; i++) {for (int x = 0; x < (1 << n); x++) {if (x & (1 << i)) {sos[x] += sos[x ^ (1 << i)];}}}
Python
sos = [0] * (1 << n)for i in range(1 << n):sos[i] = a[i]for i in range(n):for x in range(1 << n):if x & (1 << i):sos[x] += sos[x ^ (1 << i)]
General Problems
Status | Source | Problem Name | Difficulty | Tags | |
---|---|---|---|---|---|
CSES | Easy | Show TagsSOS DP | |||
Platinum | Easy | Show TagsCombo, DP | |||
CF | Normal | Show TagsBitmasks, SOS DP | |||
Platinum | Normal | Show TagsNT, Prefix Sums | |||
kilonova | Hard | Show TagsBitmasks, NT, SOS DP | |||
CF | Hard | Show TagsBitmasks, DP | |||
CF | Hard | Show TagsBitmasks, Combinatorics, DP | |||
CF | Hard | Show TagsBitmasks, DP | |||
CF | Hard | Show TagsBitmasks, DP | |||
AC | Hard | Show TagsBitmasks, DP | |||
JOI | Hard | Show TagsSOS DP | |||
CF | Insane | Show TagsBitmasks, DP, SOS DP |
Module Progress:
Join the USACO Forum!
Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!