Open In App

Count subsequences with GCD equal to X

Last Updated : 27 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given an array arr[] consisting of N integers and a positive integer X, the task is to count subsequences with GCD exactly X.

Examples:

Input: arr[] = {6, 4, 30}  X = 2
Output: 3
Explanation: Subsequences with GCD(=2) are { {6, 4, 30}, {4, 30}, {6, 4} }. Hence, 3 is the answer.

Input: arr[] = {6, 6, 6}  X = 3
Output: 0
 

Approach: The given problem can be solved with the help of Dynamic Programming. Follow the steps below to solve the given problem.

  • Define a 2-D dp table dp[i][j] which will denote the number of valid subsequences till index i with GCD(= j).
  • For each iteration we have 2 choices:
    • Take the current element: The dp table can be updated as dp[i + 1][gcd(j, arr[i])] += dp[i][j].
    • Skip the current element: The dp table can be updated as dp[i+1][j] += dp[i][j].
  • The base case is dp[0][0] = 1.
  • Since the gcd of two numbers can never be greater than the two numbers, so the values of j will be up to the maximum element in the array. Therefore,  it can be solved iteratively and the final answer will be dp[N][X].

Below is the implementation of the above approach:

C++




// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to find the total subsequences
// having GCD = X
int totalValidSubsequences(
    vector<int> arr, int X, int N)
{
    // Find the maximum element of
    // the array
    int mx = *max_element(
        arr.begin(), arr.end());
 
    // Check if X is greater than mx
    if (X > mx) {
        return 0;
    }
    // Make a 2-d dp table of
    // size [n+1, mx + 1]
    vector<vector<int> > dp(
        N + 1, vector<int>(mx + 1, 0));
 
    // Base Case
    dp[0][0] = 1;
 
    for (int i = 0; i < N; i++) {
 
        // Iterate through all possible
        // indexes
        for (int j = 0; j <= mx; j++) {
 
            // Iterate through all
            // possible values
 
            // Case 1. Skip the element
            dp[i + 1][j] += dp[i][j];
 
            // Case 2. Skip the current element
            dp[i + 1][__gcd(j, arr[i])] += dp[i][j];
        }
    }
 
    // Return the answer dp[N][X]
    return dp[N][X];
}
 
// Driver Code
int main()
{
    vector<int> arr = { 6, 4, 30 };
    int X = 2;
    int N = arr.size();
    cout << totalValidSubsequences(arr, X, N);
 
    return 0;
}


Java




// Java program for the above approach
 
import java.io.*;
import java.util.Arrays;
import java.util.Collections;
 
class GFG {
       
       // Function to find maximum in arr[]
     static int max(int[] arr)
     {
            
         // Initialize maximum element
         int max = arr[0];
         
         // Traverse array elements from second and
         // compare every element with current max 
         for (int i = 1; i < arr.length; i++)
             if (arr[i] > max)
                 max = arr[i];
         
         return max;
     }
   
      // Recursive function to return gcd of a and b
      static int gcd(int a, int b)
    {
      if (b == 0)
        return a;
      return gcd(b, a % b);
    }
 
    // Function to find the total subsequences
    // having GCD = X
    static int totalValidSubsequences(int[] arr,
                                      int X, int N)
    {
        // Find the maximum element of
        // the array
        int mx = max(arr);
 
        // Check if X is greater than mx
        if (X > mx) {
            return 0;
        }
        // Make a 2-d dp table of
        // size [n+1, mx + 1]
        int dp[][] = new int[N + 1][mx + 1];
 
        // Base Case
        dp[0][0] = 1;
 
        for (int i = 0; i < N; i++) {
 
            // Iterate through all possible
            // indexes
            for (int j = 0; j <= mx; j++) {
 
                // Iterate through all
                // possible values
 
                // Case 1. Skip the element
                dp[i + 1][j] += dp[i][j];
 
                // Case 2. Skip the current element
                dp[i + 1][gcd(j, arr[i])] += dp[i][j];
            }
        }
 
        // Return the answer dp[N][X]
        return dp[N][X];
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        int arr[] = { 6, 4, 30 };
           int X = 2;
        int N = arr.length;
           System.out.println(totalValidSubsequences(arr, X, N));
    }
}
 
// This code is contributed by Dharanendra L V.


Python3




# Python 3 program for the above approach
from math import gcd
 
# Function to find the total subsequences
# having GCD = X
def totalValidSubsequences(arr, X, N):
   
    # Find the maximum element of
    # the array
    mx = max(arr)
 
    # Check if X is greater than mx
    if (X > mx):
        return 0
    # Make a 2-d dp table of
    # size [n+1, mx + 1]
    dp = [[0 for i in range(mx+1)] for j in range(N + 1)]
 
    # Base Case
    dp[0][0] = 1
 
    for i in range(N):
       
        # Iterate through all possible
        # indexes
        for j in range(mx+1):
           
            # Iterate through all
            # possible values
 
            # Case 1. Skip the element
            dp[i + 1][j] += dp[i][j]
 
            # Case 2. Skip the current element
            dp[i + 1][gcd(j, arr[i])] += dp[i][j]
 
    # Return the answer dp[N][X]
    return dp[N][X]
 
# Driver Code
if __name__ == '__main__':
    arr = [6, 4, 30]
    X = 2
    N = len(arr)
    print(totalValidSubsequences(arr, X, N))
     
    # This code is contributed by SURENDRA_GANGWAR.


C#




// C# program for the above approach
using System;
using System.Collections.Generic;
 
class GFG{
 
       // Function to find maximum in arr[]
static int max(int []arr)
{
   
  // Initialize maximum element
  int max = arr[0];
   
  // Traverse array elements from second and
  // compare every element with current max 
  for (int i = 1; i < arr.Length; i++)
             if (arr[i] > max)
                 max = arr[i];
         
         return max;
}
 
 
// Recursive function to return gcd of a and b
static int gcd(int a, int b)
{
 if (b == 0)
        return a;
      return gcd(b, a % b);
}
 
 
// Function to find the total subsequences
// having GCD = X
static int totalValidSubsequences(int[] arr,
                                      int X, int N)
    {
        // Find the maximum element of
        // the array
        int mx = max(arr);
 
        // Check if X is greater than mx
        if (X > mx) {
            return 0;
        }
        // Make a 2-d dp table of
        // size [n+1, mx + 1]
        int[,] dp = new int[N + 1, mx + 1];
 
        // Base Case
        dp[0, 0] = 1;
 
        for (int i = 0; i < N; i++) {
 
            // Iterate through all possible
            // indexes
            for (int j = 0; j <= mx; j++) {
 
                // Iterate through all
                // possible values
 
                // Case 1. Skip the element
                dp[i + 1, j] += dp[i, j];
 
                // Case 2. Skip the current element
                dp[i + 1, gcd(j, arr[i])] += dp[i, j];
            }
        }
 
        // Return the answer dp[N][X]
        return dp[N, X];
    }
 
 
 
// Driver Code
public static void Main()
{
   int[] arr = { 6, 4, 30 };
           int X = 2;
        int N = arr.Length;
           Console.Write(totalValidSubsequences(arr, X, N));
}
}
 
// This code is contributed by _saurabh_jaiswal


Javascript




<script>
       // JavaScript Program to implement
       // the above approach
       // Recursive function to return gcd of a and b
       function __gcd(a, b) {
           if (b == 0)
               return a;
           return __gcd(b, a % b);
       }
 
 
       // Function to find the total subsequences
       // having GCD = X
       function totalValidSubsequences(
           arr, X, N)
       {
           // Find the maximum element of
           // the array
           let mx = arr[0];
 
           for (let i = 1; i < arr.length; i++) {
               mx = Math.max(mx, arr[i]);
           }
 
           // Check if X is greater than mx
           if (X > mx) {
               return 0;
           }
           // Make a 2-d dp table of
           // size [n+1, mx + 1]
 
           let dp = new Array(N + 1);
           for (let i = 0; i < N + 1; i++) {
               dp[i] = new Array(mx + 1).fill(0)
           }
 
 
           // Base Case
           dp[0][0] = 1;
 
           for (let i = 0; i < N; i++) {
 
               // Iterate through all possible
               // indexes
               for (let j = 0; j <= mx; j++) {
 
                   // Iterate through all
                   // possible values
 
                   // Case 1. Skip the element
                   dp[i + 1][j] += dp[i][j];
 
                   // Case 2. Skip the current element
                   dp[i + 1][__gcd(j, arr[i])] += dp[i][j];
               }
           }
 
           // Return the answer dp[N][X]
           return dp[N][X];
       }
 
       // Driver Code
       let arr = [6, 4, 30];
       let X = 2;
       let N = arr.length;
       document.write(totalValidSubsequences(arr, X, N));
        
    // This code is contributed by Potta Lokesh
   </script>


Output

3





Time Complexity: O(N*M), where M is the maximum element of the array.
Auxiliary Space: O(N*M)

Memoised Dynamic Programming Approach:

This approach to solve the problem is to use memoisation based approach of dynamic programming. This problem can be thought of variation of the famous DP problem of Knapsack where we have choices either to take or don’t take. Here also since we have to count subsequences we can use this approach and build up till index reaches end of the array and if gcd of that subsequence comes out to be X we can add our result count by 1.

Algorithm:

  1.     Initialize a helper function solve that takes the following parameters:
    • arr: The input array of integers.
    • X: The target GCD value.
    • N: The size of the array.
    • idx: The current index of the array being processed.
    • gcd: The current GCD value.
    • dp: A 2D vector to store the memoization table.
  2.    Check for the base case:
    • If idx is equal to N, return 1 if gcd is equal to X, indicating that a subsequence with the target GCD is found. Otherwise, return 0.
  3.    Check if the subproblem has already been solved by checking the dp table. If the value is not -1, return the precomputed result.
  4.    Recursively solve the subproblems:
    • Exclude the current element by calling solve with idx + 1, gcd, and other parameters unchanged.
    • Include the current element by calling solve with idx + 1, __gcd(gcd, arr[idx]), and other parameters unchanged.
  5.    Add the results obtained from excluding and including the current element.
  6.    Memoize the result by storing it in the dp table at position dp[idx][gcd].
  7.    Return the final result obtained from the recursive calls.
  8.    In the totalValidSubsequences function:
    • Find the maximum element in the array using the max_element function and store it in mx.
    • Create a dp table of size (N+1) x (mx+1) and initialize all values to -1.
    • Call the solve function with the appropriate parameters and store the result in count.
    • Return count as the total number of subsequences with GCD equal to X.
  9.    In the main function:
    • Define the input array arr, the target GCD X, and the size of the array N.
    • Call the totalValidSubsequences function with the input values and print the result.

Below is the implementation of the approach:

C++




// C++ code for the approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Helper function
int solve(vector<int>& arr, int X, int N, int idx, int gcd, vector<vector<int>>& dp) {
    // Base Case: If we have reached the end of the array
    if (idx == N) {
        // If the current GCD is equal to X, return 1
        if (gcd == X)
            return 1;
        return 0;
    }
 
    // Check if the subproblem is already solved
    if (dp[idx][gcd] != -1)
        return dp[idx][gcd];
 
    // Exclude the current element
    int ans = solve(arr, X, N, idx + 1, gcd, dp);
 
    // Include the current element
    ans += solve(arr, X, N, idx + 1, __gcd(gcd, arr[idx]), dp);
 
    // Memoize the result
    dp[idx][gcd] = ans;
 
    return ans;
}
 
// Function to find the total subsequences
// having GCD = X
int totalValidSubsequences(vector<int>& arr, int X, int N) {
      // store maximum element of arr in mx
      int mx = *max_element(arr.begin(), arr.end());
   
    // Create a dp-table of size (N+1) x (mx+1)
    vector<vector<int>> dp(N + 1, vector<int>(mx + 1, -1));
 
    // Call the recursive function
    int count = solve(arr, X, N, 0, 0, dp);
 
    return count;
}
 
// Driver Code
int main() {
    vector<int> arr = { 6, 4, 30 };
    int X = 2;
    int N = arr.size();
   
      // Function call
    cout << totalValidSubsequences(arr, X, N);
 
    return 0;
}
 
// This code is contributed by Chandramani Kumar


Java




import java.util.Arrays;
import java.util.Vector;
 
public class Main {
    static int MAX = 100000;
 
    // Helper function to calculate GCD
    static int gcd(int a, int b) {
        if (b == 0) {
            return a;
        }
        return gcd(b, a % b);
    }
 
    // Helper function
    static int solve(Vector<Integer> arr, int X, int N, int idx, int gcd, int[][] dp) {
        // Base Case: If we have reached the end of the array
        if (idx == N) {
            // If the current GCD is equal to X, return 1
            if (gcd == X)
                return 1;
            return 0;
        }
 
        // Check if the subproblem is already solved
        if (dp[idx][gcd] != -1)
            return dp[idx][gcd];
 
        // Exclude the current element
        int ans = solve(arr, X, N, idx + 1, gcd, dp);
 
        // Include the current element
        ans += solve(arr, X, N, idx + 1, gcd(arr.get(idx), gcd), dp);
 
        // Memoize the result
        dp[idx][gcd] = ans;
 
        return ans;
    }
 
    // Function to find the total subsequences having GCD = X
    static int totalValidSubsequences(Vector<Integer> arr, int X, int N) {
        // Find the maximum element in the array
        int mx = Integer.MIN_VALUE;
        for (int i = 0; i < N; i++) {
            mx = Math.max(mx, arr.get(i));
        }
 
        // Create a dp-table of size (N+1) x (mx+1)
        int[][] dp = new int[N + 1][mx + 1];
        for (int i = 0; i <= N; i++) {
            Arrays.fill(dp[i], -1);
        }
 
        // Call the recursive function
        int count = solve(arr, X, N, 0, 0, dp);
 
        return count;
    }
 
    // Driver Code
    public static void main(String[] args) {
        Vector<Integer> arr = new Vector<Integer>();
        arr.add(6);
        arr.add(4);
        arr.add(30);
 
        int X = 2;
        int N = arr.size();
 
        // Function call
        System.out.println(totalValidSubsequences(arr, X, N));
    }
}


Python3




import math
 
# Helper function
def solve(arr, X, N, idx, gcd, dp):
    # Base Case: If we have reached the end of the array
    if idx == N:
        # If the current GCD is equal to X, return 1
        if gcd == X:
            return 1
        return 0
 
    # Check if the subproblem is already solved
    if dp[idx][gcd] != -1:
        return dp[idx][gcd]
 
    # Exclude the current element
    ans = solve(arr, X, N, idx + 1, gcd, dp)
 
    # Include the current element
    ans += solve(arr, X, N, idx + 1, math.gcd(gcd, arr[idx]), dp)
 
    # Memoize the result
    dp[idx][gcd] = ans
 
    return ans
 
# Function to find the total subsequences
# having GCD = X
def totalValidSubsequences(arr, X, N):
    # store maximum element of arr in mx
    mx = max(arr)
 
    # Create a dp-table of size (N+1) x (mx+1)
    dp = [[-1 for _ in range(mx + 1)] for _ in range(N + 1)]
 
    # Call the recursive function
    count = solve(arr, X, N, 0, 0, dp)
 
    return count
 
# Driver Code
if __name__ == "__main__":
    arr = [6, 4, 30]
    X = 2
    N = len(arr)
 
    # Function call
    print(totalValidSubsequences(arr, X, N))


C#




using System;
using System.Collections.Generic;
 
class Program
{
    // Helper function to find the greatest common divisor (GCD)
    static int FindGCD(int a, int b)
    {
        while (b != 0)
        {
            int temp = b;
            b = a % b;
            a = temp;
        }
        return a;
    }
 
    // Helper function to find the maximum element in a list
    static int FindMax(List<int> arr)
    {
        int max = int.MinValue;
        foreach (int num in arr)
        {
            if (num > max)
                max = num;
        }
        return max;
    }
 
    // Helper function
    static int Solve(List<int> arr, int X, int N, int idx, int gcd, int[,] dp)
    {
        // Base Case: If we have reached the end of the array
        if (idx == N)
        {
            // If the current GCD is equal to X, return 1
            if (gcd == X)
                return 1;
            return 0;
        }
 
        // Check if the subproblem is already solved
        if (dp[idx, gcd] != -1)
            return dp[idx, gcd];
 
        // Exclude the current element
        int ans = Solve(arr, X, N, idx + 1, gcd, dp);
 
        // Include the current element
        ans += Solve(arr, X, N, idx + 1, FindGCD(gcd, arr[idx]), dp);
 
        // Memoize the result
        dp[idx, gcd] = ans;
 
        return ans;
    }
 
    // Function to find the total subsequences having GCD = X
    static int TotalValidSubsequences(List<int> arr, int X, int N)
    {
        // Find the maximum element in the array
        int mx = FindMax(arr);
 
        // Create a dp-table of size (N+1) x (mx+1)
        int[,] dp = new int[N + 1, mx + 1];
        for (int i = 0; i <= N; i++)
        {
            for (int j = 0; j <= mx; j++)
            {
                dp[i, j] = -1;
            }
        }
 
        // Call the recursive function
        int count = Solve(arr, X, N, 0, 0, dp);
 
        return count;
    }
 
    static void Main()
    {
        List<int> arr = new List<int> { 6, 4, 30 };
        int X = 2;
        int N = arr.Count;
 
        // Function call
        Console.WriteLine(TotalValidSubsequences(arr, X, N));
    }
}


Javascript




const MAX = 100000;
 
// Helper function to calculate GCD
function gcd(a, b) {
    if (b === 0) {
        return a;
    }
    return gcd(b, a % b);
}
 
// Helper function
function solve(arr, X, N, idx, currentGcd, dp) {
    // Base Case: If we have reached the end of the array
    if (idx === N) {
        // If the current GCD is equal to X, return 1
        if (currentGcd === X) {
            return 1;
        }
        return 0;
    }
 
    // Check if the subproblem is already solved
    if (dp[idx][currentGcd] !== -1) {
        return dp[idx][currentGcd];
    }
 
    // Exclude the current element
    let ans = solve(arr, X, N, idx + 1, currentGcd, dp);
 
    // Include the current element
    ans += solve(arr, X, N, idx + 1, gcd(arr[idx], currentGcd), dp);
 
    // Memoize the result
    dp[idx][currentGcd] = ans;
 
    return ans;
}
 
// Function to find the total subsequences having GCD = X
function totalValidSubsequences(arr, X, N) {
    // Find the maximum element in the array
    let mx = Math.max(...arr);
 
    // Create a dp-table of size (N+1) x (mx+1)
    let dp = Array.from(Array(N + 1), () => Array(mx + 1).fill(-1));
 
    // Call the recursive function
    let count = solve(arr, X, N, 0, 0, dp);
 
    return count;
}
 
// Driver Code
const arr = [6, 4, 30];
const X = 2;
const N = arr.length;
 
// Function call
console.log(totalValidSubsequences(arr, X, N));


Output

3





Time Complexity: O(N*M), where N is size of input array and M is the maximum element of the array.

Auxiliary Space: O(N*M) where N is size of input array and M is the maximum element of the array. This is because 2D dp array has been created.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads