Count subsequences with GCD equal to X
Last Updated :
27 Nov, 2023
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++
#include <bits/stdc++.h>
using namespace std;
int totalValidSubsequences(
vector< int > arr, int X, int N)
{
int mx = *max_element(
arr.begin(), arr.end());
if (X > mx) {
return 0;
}
vector<vector< int > > dp(
N + 1, vector< int >(mx + 1, 0));
dp[0][0] = 1;
for ( int i = 0; i < N; i++) {
for ( int j = 0; j <= mx; j++) {
dp[i + 1][j] += dp[i][j];
dp[i + 1][__gcd(j, arr[i])] += dp[i][j];
}
}
return dp[N][X];
}
int main()
{
vector< int > arr = { 6, 4, 30 };
int X = 2;
int N = arr.size();
cout << totalValidSubsequences(arr, X, N);
return 0;
}
|
Java
import java.io.*;
import java.util.Arrays;
import java.util.Collections;
class GFG {
static int max( int [] arr)
{
int max = arr[ 0 ];
for ( int i = 1 ; i < arr.length; i++)
if (arr[i] > max)
max = arr[i];
return max;
}
static int gcd( int a, int b)
{
if (b == 0 )
return a;
return gcd(b, a % b);
}
static int totalValidSubsequences( int [] arr,
int X, int N)
{
int mx = max(arr);
if (X > mx) {
return 0 ;
}
int dp[][] = new int [N + 1 ][mx + 1 ];
dp[ 0 ][ 0 ] = 1 ;
for ( int i = 0 ; i < N; i++) {
for ( int j = 0 ; j <= mx; j++) {
dp[i + 1 ][j] += dp[i][j];
dp[i + 1 ][gcd(j, arr[i])] += dp[i][j];
}
}
return dp[N][X];
}
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));
}
}
|
Python3
from math import gcd
def totalValidSubsequences(arr, X, N):
mx = max (arr)
if (X > mx):
return 0
dp = [[ 0 for i in range (mx + 1 )] for j in range (N + 1 )]
dp[ 0 ][ 0 ] = 1
for i in range (N):
for j in range (mx + 1 ):
dp[i + 1 ][j] + = dp[i][j]
dp[i + 1 ][gcd(j, arr[i])] + = dp[i][j]
return dp[N][X]
if __name__ = = '__main__' :
arr = [ 6 , 4 , 30 ]
X = 2
N = len (arr)
print (totalValidSubsequences(arr, X, N))
|
C#
using System;
using System.Collections.Generic;
class GFG{
static int max( int []arr)
{
int max = arr[0];
for ( int i = 1; i < arr.Length; i++)
if (arr[i] > max)
max = arr[i];
return max;
}
static int gcd( int a, int b)
{
if (b == 0)
return a;
return gcd(b, a % b);
}
static int totalValidSubsequences( int [] arr,
int X, int N)
{
int mx = max(arr);
if (X > mx) {
return 0;
}
int [,] dp = new int [N + 1, mx + 1];
dp[0, 0] = 1;
for ( int i = 0; i < N; i++) {
for ( int j = 0; j <= mx; j++) {
dp[i + 1, j] += dp[i, j];
dp[i + 1, gcd(j, arr[i])] += dp[i, j];
}
}
return dp[N, X];
}
public static void Main()
{
int [] arr = { 6, 4, 30 };
int X = 2;
int N = arr.Length;
Console.Write(totalValidSubsequences(arr, X, N));
}
}
|
Javascript
<script>
function __gcd(a, b) {
if (b == 0)
return a;
return __gcd(b, a % b);
}
function totalValidSubsequences(
arr, X, N)
{
let mx = arr[0];
for (let i = 1; i < arr.length; i++) {
mx = Math.max(mx, arr[i]);
}
if (X > mx) {
return 0;
}
let dp = new Array(N + 1);
for (let i = 0; i < N + 1; i++) {
dp[i] = new Array(mx + 1).fill(0)
}
dp[0][0] = 1;
for (let i = 0; i < N; i++) {
for (let j = 0; j <= mx; j++) {
dp[i + 1][j] += dp[i][j];
dp[i + 1][__gcd(j, arr[i])] += dp[i][j];
}
}
return dp[N][X];
}
let arr = [6, 4, 30];
let X = 2;
let N = arr.length;
document.write(totalValidSubsequences(arr, X, N));
</script>
|
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:
- 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.
- 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.
- Check if the subproblem has already been solved by checking the dp table. If the value is not -1, return the precomputed result.
- 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.
- Add the results obtained from excluding and including the current element.
- Memoize the result by storing it in the dp table at position dp[idx][gcd].
- Return the final result obtained from the recursive calls.
- 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.
- 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++
#include <bits/stdc++.h>
using namespace std;
int solve(vector< int >& arr, int X, int N, int idx, int gcd, vector<vector< int >>& dp) {
if (idx == N) {
if (gcd == X)
return 1;
return 0;
}
if (dp[idx][gcd] != -1)
return dp[idx][gcd];
int ans = solve(arr, X, N, idx + 1, gcd, dp);
ans += solve(arr, X, N, idx + 1, __gcd(gcd, arr[idx]), dp);
dp[idx][gcd] = ans;
return ans;
}
int totalValidSubsequences(vector< int >& arr, int X, int N) {
int mx = *max_element(arr.begin(), arr.end());
vector<vector< int >> dp(N + 1, vector< int >(mx + 1, -1));
int count = solve(arr, X, N, 0, 0, dp);
return count;
}
int main() {
vector< int > arr = { 6, 4, 30 };
int X = 2;
int N = arr.size();
cout << totalValidSubsequences(arr, X, N);
return 0;
}
|
Java
import java.util.Arrays;
import java.util.Vector;
public class Main {
static int MAX = 100000 ;
static int gcd( int a, int b) {
if (b == 0 ) {
return a;
}
return gcd(b, a % b);
}
static int solve(Vector<Integer> arr, int X, int N, int idx, int gcd, int [][] dp) {
if (idx == N) {
if (gcd == X)
return 1 ;
return 0 ;
}
if (dp[idx][gcd] != - 1 )
return dp[idx][gcd];
int ans = solve(arr, X, N, idx + 1 , gcd, dp);
ans += solve(arr, X, N, idx + 1 , gcd(arr.get(idx), gcd), dp);
dp[idx][gcd] = ans;
return ans;
}
static int totalValidSubsequences(Vector<Integer> arr, int X, int N) {
int mx = Integer.MIN_VALUE;
for ( int i = 0 ; i < N; i++) {
mx = Math.max(mx, arr.get(i));
}
int [][] dp = new int [N + 1 ][mx + 1 ];
for ( int i = 0 ; i <= N; i++) {
Arrays.fill(dp[i], - 1 );
}
int count = solve(arr, X, N, 0 , 0 , dp);
return count;
}
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();
System.out.println(totalValidSubsequences(arr, X, N));
}
}
|
Python3
import math
def solve(arr, X, N, idx, gcd, dp):
if idx = = N:
if gcd = = X:
return 1
return 0
if dp[idx][gcd] ! = - 1 :
return dp[idx][gcd]
ans = solve(arr, X, N, idx + 1 , gcd, dp)
ans + = solve(arr, X, N, idx + 1 , math.gcd(gcd, arr[idx]), dp)
dp[idx][gcd] = ans
return ans
def totalValidSubsequences(arr, X, N):
mx = max (arr)
dp = [[ - 1 for _ in range (mx + 1 )] for _ in range (N + 1 )]
count = solve(arr, X, N, 0 , 0 , dp)
return count
if __name__ = = "__main__" :
arr = [ 6 , 4 , 30 ]
X = 2
N = len (arr)
print (totalValidSubsequences(arr, X, N))
|
C#
using System;
using System.Collections.Generic;
class Program
{
static int FindGCD( int a, int b)
{
while (b != 0)
{
int temp = b;
b = a % b;
a = temp;
}
return a;
}
static int FindMax(List< int > arr)
{
int max = int .MinValue;
foreach ( int num in arr)
{
if (num > max)
max = num;
}
return max;
}
static int Solve(List< int > arr, int X, int N, int idx, int gcd, int [,] dp)
{
if (idx == N)
{
if (gcd == X)
return 1;
return 0;
}
if (dp[idx, gcd] != -1)
return dp[idx, gcd];
int ans = Solve(arr, X, N, idx + 1, gcd, dp);
ans += Solve(arr, X, N, idx + 1, FindGCD(gcd, arr[idx]), dp);
dp[idx, gcd] = ans;
return ans;
}
static int TotalValidSubsequences(List< int > arr, int X, int N)
{
int mx = FindMax(arr);
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;
}
}
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;
Console.WriteLine(TotalValidSubsequences(arr, X, N));
}
}
|
Javascript
const MAX = 100000;
function gcd(a, b) {
if (b === 0) {
return a;
}
return gcd(b, a % b);
}
function solve(arr, X, N, idx, currentGcd, dp) {
if (idx === N) {
if (currentGcd === X) {
return 1;
}
return 0;
}
if (dp[idx][currentGcd] !== -1) {
return dp[idx][currentGcd];
}
let ans = solve(arr, X, N, idx + 1, currentGcd, dp);
ans += solve(arr, X, N, idx + 1, gcd(arr[idx], currentGcd), dp);
dp[idx][currentGcd] = ans;
return ans;
}
function totalValidSubsequences(arr, X, N) {
let mx = Math.max(...arr);
let dp = Array.from(Array(N + 1), () => Array(mx + 1).fill(-1));
let count = solve(arr, X, N, 0, 0, dp);
return count;
}
const arr = [6, 4, 30];
const X = 2;
const N = arr.length;
console.log(totalValidSubsequences(arr, X, N));
|
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.
Share your thoughts in the comments
Please Login to comment...