Open In App

Count number of distinct sum subsets within given range

Last Updated : 07 Mar, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given a set S of N numbers and a range specified by two numbers L (Lower Bound) and R (Upper Bound). Find the number of distinct values of all possible sums of some subset of S that lie between the given range. Examples :

Input : S = { 1, 2, 2, 3, 5 }, L = 1 and R = 5
Output : 5
Explanation :  Every number between 
1 and 5 can be made out using some subset of S.
{1 as 1, 2 as 2, 3 as 3, 4 as 2 + 2 and 5 as 5} 

Input : S = { 2, 3, 5 }, L = 1 and R = 7
Output : 4
Explanation :  Only 4 numbers between 
1 and 7 can be made out, i.e. {2, 3, 5, 7}. 
3 numbers which are {1, 4, 6} can't be made out in any way.

Prerequisites : Bitset | Bit Manipulation 

Method 1(Simple) : A naive approach is to generate all possible subsets of given set, calculate their sum subset wise and push them into a hashmap. Iterate over the complete given range and count the numbers which exists in the hashmap. Method 2(Efficient) : An efficient way to solve this problem is by using bitset of size 105. Update the bitset for every element X by left shifting the bitset and doing bitwise OR with previous bitset so that the bitset at the new possible sums become 1. Then by using the concept of Prefix Sums, precompute the required count of numbers between 1 and i for prefix[1..i] to answer each query in O(1) if there are more than query being asked simultaneously. For a query L and R, answer would be simply prefix[R] – prefix[L – 1]

For e.g. S = { 2, 3, 5 }, L = 1 and R = 7 Considering a bitset of size 32 for simplicity. Initially 1 is at 0th position of bitset 00000000000000000000000000000001 For incoming 2, left shifting the bitset by 2 and doing OR with previous bitset 00000000000000000000000000000101 Similarly for 3, 00000000000000000000000000101101 for 5, 00000000000000000000010110101101 This final bitset contains 1 at those positions(possible sums) which can be made out using some subset of S. Hence between position 1 and 7, there are 4 set bits, thus the required answer.

Steps to solve the problem:

  •  Initialize a bitset BS of size SZ, where SZ is a large enough constant. Initialize the 0th position of the bitset to 1.
  •  Iterate over the elements S[i] of S from 0 to N-1.
    • Left shift the bitset BS by S[i] positions and take the bitwise OR with the previous bitset BS. 
  • Initialize an array prefix of size SZ, and initialize all elements to 0.
  • Iterate over the elements of prefix from 1 to SZ-1.
    • Set prefix[i] = prefix[i-1] + BS[i].
  • Calculate the answer as prefix[R] – prefix[L-1].
  •  Return the answer.

Below is the implementation of above approach in C++ : 

CPP




// CPP Program to count the number
// distinct values of sum of some
// subset in a range
#include <bits/stdc++.h>
 
using namespace std;
 
// Constant size for bitset
#define SZ 100001
 
int countOfpossibleNumbers(int S[], int N,
                           int L, int R)
{
    // Creating a bitset of size SZ
    bitset <SZ> BS;
     
    // Set 0th position to 1
    BS[0] = 1;
     
    // Build the bitset
    for (int i = 0; i < N; i++) {
         
        // Left shift the bitset for each
        // element and taking bitwise OR
        // with previous bitset
        BS = BS | (BS << S[i]);
    }
     
    int prefix[SZ];
     
    // Initializing the prefix array to zero
    memset(prefix, 0, sizeof(prefix));
     
    // Build the prefix array
    for (int i = 1; i < SZ; i++) {
        prefix[i] = prefix[i - 1] + BS[i];
    }
     
    // Answer the given query
    int ans = prefix[R] - prefix[L - 1];
     
    return ans;
}
 
// Driver Code to test above functions
int main()
{
    int S[] = { 1, 2, 3, 5, 7 };
    int N = sizeof(S) / sizeof(S[0]);
     
    int L = 1, R = 18;
     
    cout << countOfpossibleNumbers(S, N, L, R);
         
    return 0;
}


Java




// Java Program to count the number
// distinct values of sum of some
// subset in a range
 
import java.util.*;
import java.lang.*;
import java.io.*;
 
 
class GFG
{
   
    // Constant size for bitset
    static int SZ = 100001;
 
    static int countOfpossibleNumbers(int[] S, int N, int L,
                                      int R)
    {
 
        // Initially BS is 1
        int BS = 1;
 
        for (int i = 0; i < N; i++) {
 
            // Left shift the bitset for each
            // element and taking bitwise OR
            // with previous bitset
            BS = BS | (BS << S[i]);
        }
 
        // Convert BS to bitset array
        String BS_ = Integer.toBinaryString(BS);
        BS_ = String.format("%" + (-SZ) + "s", BS_).replace(' ', '0');
 
 
        // Initializing the prefix array to zero
        int[] prefix = new int[SZ];
        for (int i = 0; i < SZ; i++)
            prefix[i] = 0;
 
        // Build the prefix array
        for (var i = 1; i < SZ; i++) {
            prefix[i]
                = prefix[i - 1] + ((BS_.charAt(i) == '1') ? 1 : 0);
        }
 
        // Answer the given query
        int ans = prefix[R] - prefix[L - 1];
 
        return ans;
    }
 
    // Driver Code to test above functions
    public static void main(String[] args)
    {
        int[] S = { 1, 2, 3, 5, 7 };
        int N = S.length;
 
        int L = 1;
        int R = 18;
 
        // Function call
        System.out.println(countOfpossibleNumbers(S, N, L, R));
    }
}
 
// This code is contributed by phasing17


Python3




# Python3 Program to count the number
# distinct values of sum of some
# subset in a range
 
# Constant size for bitset
SZ = 100001
 
def countOfpossibleNumbers(S, N, L, R):
 
    # Initially BS is 1
    BS = 1
 
    for i in range(N):
 
        # Left shift the bitset for each
        # element and taking bitwise OR
        # with previous bitset
        BS = BS | (BS << S[i])
 
    # Convert BS to bitset array
    BS = bin(BS)[2::]
    BS = [int(i) for i in BS.zfill(SZ)][::-1]
 
    # Initializing the prefix array to zero
    prefix = [0 for i in range(SZ)]
 
    # Build the prefix array
    for i in range(1, SZ):
        prefix[i] = prefix[i - 1] + BS[i]
 
    # Answer the given query
    ans = prefix[R] - prefix[L - 1]
 
    return ans
 
# Driver Code to test above functions
S = [1, 2, 3, 5, 7]
N = len(S)
L, R = 1, 18
 
print(countOfpossibleNumbers(S, N, L, R))
 
# This code is contributed by phasing17


C#




// C# Program to count the number
// distinct values of sum of some
// subset in a range
using System;
class GFG
{
   
    // Constant size for bitset
    static int SZ = 100001;
 
    static int countOfpossibleNumbers(int[] S, int N, int L,
                                      int R)
    {
 
        // Initially BS is 1
        int BS = 1;
 
        for (int i = 0; i < N; i++) {
 
            // Left shift the bitset for each
            // element and taking bitwise OR
            // with previous bitset
            BS = BS | (BS << S[i]);
        }
 
        // Convert BS to bitset array
        string BS_ = Convert.ToString(BS, 2);
        BS_ = BS_.PadRight(SZ, '0');
 
        // Initializing the prefix array to zero
        int[] prefix = new int[SZ];
        for (int i = 0; i < SZ; i++)
            prefix[i] = 0;
 
        // Build the prefix array
        for (var i = 1; i < SZ; i++) {
            prefix[i]
                = prefix[i - 1] + ((BS_[i] == '1') ? 1 : 0);
        }
 
        // Answer the given query
        int ans = prefix[R] - prefix[L - 1];
 
        return ans;
    }
 
    // Driver Code to test above functions
    public static void Main(string[] args)
    {
        int[] S = { 1, 2, 3, 5, 7 };
        int N = S.Length;
 
        int L = 1;
        int R = 18;
 
        // Function call
        Console.WriteLine(
            countOfpossibleNumbers(S, N, L, R));
    }
}
 
// This code is contributed by phasing17


Javascript




// JS Program to count the number
// distinct values of sum of some
// subset in a range
 
// Constant size for bitset
const SZ = 100001;
 
function countOfpossibleNumbers(S, N, L, R)
{
 
    //Initially BS is 1
    var BS  = 1;
     
     
    for (var i = 0; i < N; i++) {
         
        // Left shift the bitset for each
        // element and taking bitwise OR
        // with previous bitset
        BS = BS | (BS << S[i]);
    }
     
    //Convert BS to bitset array
    BS = BS.toString(2);
    BS = BS.padEnd(SZ, "0");
    BS = BS.split("");
    BS = BS.map(str => {
  return Number(str);
});
     
    // Initializing the prefix array to zero
    var prefix = new Array(SZ).fill(0);
 
     
    // Build the prefix array
    for (var i = 1; i < SZ; i++) {
        prefix[i] = prefix[i - 1] + BS[i];
    }
 
    // Answer the given query
    var ans = prefix[R] - prefix[L - 1];
 
    return ans;
}
 
// Driver Code to test above functions
var S = [ 1, 2, 3, 5, 7 ];
var N = S.length;
     
var L = 1;
var R = 18;
     
console.log(countOfpossibleNumbers(S, N, L, R));
 
// This code is contributed by phasing17


Output:

18

Time Complexity: O(S*Z) where S*Z is the maximum sum for given constraints, i.e. 105



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads