Count subsets consisting of each element as a factor of the next element in that subset

• Difficulty Level : Medium
• Last Updated : 24 Sep, 2021

Given an array arr[] of size N, the task is to find the number of non-empty subsets present in the array such that every element( except the last) in the subset is a factor of the next adjacent element present in that subset. The elements in a subset can be rearranged, therefore, if any rearrangement of a subset satisfies the condition, then that subset will be counted in. However, this subset should be counted in only once.

Examples:

Input: arr[] = {2, 3, 6, 8}
Output: 7
Explanation:
The required subsets are: {2}, {3}, {6}, {8}, {2, 6}, {8, 2}, {3, 6}.
Since subsets {2}, {3}, {6}, {8} contains a single number, they are included in the answer.
In the subset {2, 6}, 2 is a factor of 6.
In the subset {3, 6}, 3 is a factor of 6.
{8, 2} when rearranged into {2, 8}, satisfies the required condition.

Input: arr[] = {16, 18, 6, 7, 2, 19, 20, 9}
Output: 15

Naive Approach: The simplest idea is to generate all possible subsets of the array and print the count of those subsets whose adjacent element (arr[i], arr[i + 1]), arr[i] is a factor of arr[i + 1].

Below is the implementation of the above approach:

C++

 // C++ program for the above approach #include #define mod 1000000007using namespace std; // Function to calculate each subset// for the array using bit maskingset getSubset(int n, int* arr,                   int mask){    // Stores the unique elements    // of the array arr[]    set subset;     // Traverse the array    for (int i = 0; i < n; i++) {         // Get the ith bit of the mask        int b = (mask & (1 << i));         // ith bit of mask is set then        // include the corresponding        // element in subset        if (b != 0) {            subset.insert(arr[i]);        }    }    return subset;} // Function to count the subsets// that satisfy the given conditionint countSets(int n, set* power_set){    // Store the count of subsets    int count = 0;     // Iterate through all the sets    // in the power set    for (int i = 1; i < (1 << n); i++) {         // Initially, set flag as true        bool flag = true;         int N = power_set[i].size();         // Convert the current subset        // into an array        int* temp = new int[N];         auto it = power_set[i].begin();         for (int j = 0;             it != power_set[i].end();             j++, it++) {            temp[j] = *it;        }         // Check for any index, i,        // a[i] is a factor of a[i+1]        for (int k1 = 1, k0 = 0; k1 < N;) {             if (temp[k1] % temp[k0] != 0) {                flag = false;                break;            }            if (k0 > 0)                k0--;            else {                k1++;                k0 = k1 - 1;            }        }         // If flag is stil set, then        // update the count        if (flag)            count = 1LL * (count + 1) % mod;         delete[] temp;    }     // Return the final count    return count;} // Function to generate power set of// the given array arr[]void generatePowerSet(int arr[], int n){     // Declare power set of size 2^n    set* power_set        = new set[1 << n];     // Represent each subset using    // some mask    int mask = 0;    for (int i = 0; i < (1 << n); i++) {        power_set[i] = getSubset(n, arr, mask);        mask++;    }     // Find the required number of    // subsets    cout << countSets(n, power_set) % mod;     delete[] power_set;} // Driver Codeint main(){    int arr[] = { 16, 18, 6, 7, 2, 19, 20, 9 };    int N = sizeof(arr) / sizeof(arr);     // Function Call    generatePowerSet(arr, N);     return 0;}
Output:
15

Time Complexity: O(N*2N)
Auxiliary Space: O(1)

HashMap-based Approach: To optimize the above approach, the idea is to use a hashmap and an array dp[] to store the array elements in a sorted manner and keeps a count of the subsets as well. For index i, dp[arr[i]] will store the number of all subsets satisfying the given conditions ending at index i. Follow the steps below to solve the problem:

• Initialize cnt as 0 to store the number of required subsets.
• Initialize a hashmap, dp and mark dp[arr[i]] with 1 for every i over the range [0, N – 1].
• Traverse the array dp[] using the variable i and nested traverse from i to begin using iterator j and if i is not equal to j, and element at j is a factor of the element at i, then update dp[i] += dp[j].
• Again, traverse the map and update cnt as cnt += dp[i].
• After the above steps, print the value of cnt as the result.

Below is the implementation of the above approach:

C++

 // C++ program for the above approach#include #define mod 1000000007using namespace std; // Function that counts subsets whose// every element is divisible by the// previous adjacent elementvoid countSets(int* arr, int n){    // Declare a map    map dp;     // Initialise dp[arr[i]] with 1    for (int i = 0; i < n; i++)        dp[arr[i]] = 1;     // Traverse the map till end    map::iterator i = dp.begin();     for (; i != dp.end(); i++) {         // Traverse the map from i to        // begin using iterator j        map::iterator j = i;         for (; j != dp.begin(); j--) {             if (i == j)                continue;             // Check if condition is true            if (i->first % j->first == 0) {                 // If factor found, append                // i at to all subsets                i->second                    = (i->second % mod                       + j->second % mod)                      % mod;            }        }         // Check for the first element        // of the map        if (i != j            && i->first % j->first == 0) {            i->second                = (i->second % mod                   + j->second % mod)                  % mod;        }    }     // Store count of required subsets    int cnt = 0;     // Traverse the map    for (i = dp.begin(); i != dp.end(); i++)         // Update the cnt variable        cnt = (cnt % mod               + i->second % mod)              % mod;     // Print the result    cout << cnt % mod;} // Driver Codeint main(){    int arr[] = { 16, 18, 6, 7, 2, 19, 20, 9 };    int N = sizeof(arr) / sizeof(arr);     // Function Call    countSets(arr, N);     return 0;}

Output:
15

Time Complexity: O(N2)
Auxiliary Space: O(N)

Efficient Approach: To optimize the above approach, the idea is to use the similar concept to Sieve of Eratosthenes. Follow the steps below to solve the problem:

• Create an array sieve[] of size greatest element in the array(say maxE), arr[] and initialize with 0s.
• Set sieve[i] = 1 where i is the elements of the array.
• Traverse the array sieve[] over the range [1, maxE]using the variable i and if the value of sieve[i] is positive then add the sieve[i] to all the multiples of i(say j) if the sieve[j] is positive.
• After completing the above steps, print the sum of the elements of the array sieve[] as the result.

Below is the implementation of the above approach:

C++

 // C++ program for the above approach#include #define mod 1000000007using namespace std; // Function to find number of subsets// satisfying the given conditionvoid countSets(int* arr, int n){    // Stores number of required sets    int cnt = 0;     // Stores maximum element of arr[]    // that defines the size of sieve    int maxE = -1;     // Iterate through the arr[]    for (int i = 0; i < n; i++) {         // If current element > maxE,        // then update maxE        if (maxE < arr[i])            maxE = arr[i];    }     // Declare an array sieve of size N + 1    int* sieve = new int[maxE + 1];     // Initialize with all 0s    for (int i = 0; i <= maxE; i++)        sieve[i] = 0;     // Mark all elements corresponding in    // the array, by one as there will    // always exists a singleton set    for (int i = 0; i < n; i++)        sieve[arr[i]] = 1;     // Iterate from range [1, N]    for (int i = 1; i <= maxE; i++) {         // If element is present in array        if (sieve[i] != 0) {             // Traverse through all its            // multiples <= n            for (int j = i * 2; j <= maxE; j += i) {                 // Update them if they                // are present in array                if (sieve[j] != 0)                    sieve[j] = (sieve[j] + sieve[i])                               % mod;            }        }    }     // Iterate from the range [1, N]    for (int i = 0; i <= maxE; i++)         // Update the value of cnt        cnt = (cnt % mod + sieve[i] % mod) % mod;     delete[] sieve;     // Print the result    cout << cnt % mod;} // Driver Codeint main(){    int arr[] = { 16, 18, 6, 7, 2, 19, 20, 9 };    int N = sizeof(arr) / sizeof(arr);     // Function Call    countSets(arr, N);     return 0;}

Java

 // Java Program to implement// the above approachimport java.io.*;import java.util.*; class GFG {   static int mod = 1000000007;   // Function to find number of subsets  // satisfying the given condition  static void countSets(int arr[], int n)  {    // Stores number of required sets    int cnt = 0;     // Stores maximum element of arr[]    // that defines the size of sieve    int maxE = -1;     // Iterate through the arr[]    for (int i = 0; i < n; i++) {       // If current element > maxE,      // then update maxE      if (maxE < arr[i])        maxE = arr[i];    }     // Declare an array sieve of size N + 1    int sieve[] = new int[maxE + 1];     // Mark all elements corresponding in    // the array, by one as there will    // always exists a singleton set    for (int i = 0; i < n; i++)      sieve[arr[i]] = 1;     // Iterate from range [1, N]    for (int i = 1; i <= maxE; i++) {       // If element is present in array      if (sieve[i] != 0) {         // Traverse through all its        // multiples <= n        for (int j = i * 2; j <= maxE; j += i) {           // Update them if they          // are present in array          if (sieve[j] != 0)            sieve[j]            = (sieve[j] + sieve[i]) % mod;        }      }    }     // Iterate from the range [1, N]    for (int i = 0; i <= maxE; i++)       // Update the value of cnt      cnt = (cnt % mod + sieve[i] % mod) % mod;     // Print the result    System.out.println(cnt % mod);  }   // Driver Code  public static void main(String[] args)  {     int arr[] = { 16, 18, 6, 7, 2, 19, 20, 9 };    int N = arr.length;     // Function Call    countSets(arr, N);  }} // This code is contributed by Kingash.

Python3

 #mod 1000000007 # Function to find number of subsets# satisfying the given conditiondef countSets(arr, n):       # Stores number of required sets    cnt = 0     # Stores maximum element of arr[]    # that defines the size of sieve    maxE = -1     # Iterate through the arr[]    for i in range(n):         # If current element > maxE,        # then update maxE        if (maxE < arr[i]):            maxE = arr[i]     # Declare an array sieve of size N + 1    sieve = *(maxE + 1)     # Mark all elements corresponding in    # the array, by one as there will    # always exists a singleton set    for i in range(n):        sieve[arr[i]] = 1     # Iterate from range [1, N]    for i in range(1, maxE + 1):         # If element is present in array        if (sieve[i] != 0):             # Traverse through all its            # multiples <= n            for j in range(i * 2, maxE + 1, i):                 # Update them if they                # are present in array                if (sieve[j] != 0):                    sieve[j] = (sieve[j] + sieve[i])% 1000000007     # Iterate from the range [1, N]    for i in range(maxE + 1):               # Update the value of cnt        cnt = (cnt % 1000000007 + sieve[i] % 1000000007) % 1000000007     #delete[] sieve     # Prthe result    print (cnt % 1000000007) # Driver Codeif __name__ == '__main__':    arr =[16, 18, 6, 7, 2, 19, 20, 9]    N = len(arr)     # Function Call    countSets(arr, N) # This code is contributed by mohit kumar 29.

C#

 // C# Program to implement// the above approachusing System; class GFG {   static int mod = 1000000007;   // Function to find number of subsets  // satisfying the given condition  static void countSets(int[] arr, int n)  {    // Stores number of required sets    int cnt = 0;     // Stores maximum element of arr[]    // that defines the size of sieve    int maxE = -1;     // Iterate through the arr[]    for (int i = 0; i < n; i++) {       // If current element > maxE,      // then update maxE      if (maxE < arr[i])        maxE = arr[i];    }     // Declare an array sieve of size N + 1    int[] sieve = new int[maxE + 1];     // Mark all elements corresponding in    // the array, by one as there will    // always exists a singleton set    for (int i = 0; i < n; i++)      sieve[arr[i]] = 1;     // Iterate from range [1, N]    for (int i = 1; i <= maxE; i++) {       // If element is present in array      if (sieve[i] != 0) {         // Traverse through all its        // multiples <= n        for (int j = i * 2; j <= maxE; j += i) {           // Update them if they          // are present in array          if (sieve[j] != 0)            sieve[j]            = (sieve[j] + sieve[i]) % mod;        }      }    }     // Iterate from the range [1, N]    for (int i = 0; i <= maxE; i++)       // Update the value of cnt      cnt = (cnt % mod + sieve[i] % mod) % mod;     // Print the result    Console.WriteLine(cnt % mod);  }   // Driver Code  public static void Main(string[] args)  {     int[] arr = { 16, 18, 6, 7, 2, 19, 20, 9 };    int N = arr.Length;     // Function Call    countSets(arr, N);  }} // This code is contributed by ukasp.

Javascript



Output:
15

Time Complexity: O(maxE*log(log (maxE)))
Auxiliary Space: O(maxE)

My Personal Notes arrow_drop_up