Game Of Multiplicity- DP on Subsequences

Last Updated : 23 Dec, 2025

Given an array A of n integers.

A sequence B is called a subsequence of A if it can be obtained by deleting zero or more elements from A without changing the order of the remaining elements.

A subsequence B = [b₁, b₂, …, bₖ] is called good if:

The subsequence is non-empty and for every position i (1-indexed), bᵢ is divisible by i

The task is to find the total number of good subsequences of the array A.

Since the result can be large, output the answer modulo 10^9 + 7.

Example:

Input : n = 5, a[] = [2, 2, 1, 22, 14]

Output : 13

Explanation : The possible good subsequences

are: {2}, {2,2}, {2,22}, {2,14}, {2}, {2,22}, {2,14},

{1}, {1,22}, {1,14}, {22}, {22,14}, {14}.

Note, that some subsequences are listed more than once,

since they occur in the original array multiple times.

[Naive Approach] Generating All Subsequences O(N * 2^N) Time and O(N · 2^N) Space

In this approach, we generate all possible subsequences of the given array. Each element can either be included or excluded, resulting in 2^N total subsequences. For every non-empty subsequence, we verify whether the element at position i is divisible by i. If the condition is satisfied for all positions, the subsequence is counted as good. Although intuitive, this approach is inefficient because of its exponential time complexity

C++
#include <bits/stdc++.h>
using namespace std;


bool isGood(vector<int>& b) {
    for (int i = 0; i < b.size(); i++) {
        if (b[i] % (i + 1) != 0) return false;
    }
    return true;
}


int countGood(int idx, vector<int>& a, vector<int>& cur) {
    if (idx == a.size()) {
        
        // empty not allowed
        if (cur.empty()) return 0;        
        return isGood(cur) ? 1 : 0;
    }

    // skip
    int ans = countGood(idx + 1, a, cur);

    // take
    cur.push_back(a[idx]);
    ans += countGood(idx + 1, a, cur);
    cur.pop_back();

    return ans;
}

int main() {
    vector<int> a = {2, 2, 1, 22, 14};
    vector<int> cur;
    cout << countGood(0, a, cur);
    return 0;
}
Java
import java.util.*;

class GFG {

    static boolean isGood(List<Integer> b) {
        for (int i = 0; i < b.size(); i++) {
            if (b.get(i) % (i + 1) != 0) return false;
        }
        return true;
    }

    static int countGood(int idx, int[] a, List<Integer> cur) {
        if (idx == a.length) {
            
            // empty not allowed
            if (cur.isEmpty()) return 0;
            return isGood(cur) ? 1 : 0;
        }

        // skip
        int ans = countGood(idx + 1, a, cur); 

        // take
        cur.add(a[idx]);                      
        ans += countGood(idx + 1, a, cur);
        cur.remove(cur.size() - 1);

        return ans;
    }

    public static void main(String[] args) {
        int[] a = {2, 2, 1, 22, 14};
        System.out.println(countGood(0, a, new ArrayList<>()));
    }
}
Python
def is_good(b):
    for i in range(len(b)):
        if b[i] % (i + 1) != 0:
            return False
    return True

def count_good(idx, a, cur):
    if idx == len(a):
        if not cur:
            return 0
        return 1 if is_good(cur) else 0

    # skip 
    ans = count_good(idx + 1, a, cur)

    # take
    cur.append(a[idx])
    ans += count_good(idx + 1, a, cur)
    cur.pop()

    return ans

if __name__ == "__main__":
    a = [2, 2, 1, 22, 14]
    print(count_good(0, a, []))
C#
using System;
using System.Collections.Generic;

class GFG {

    static bool IsGood(List<int> b) {
        for (int i = 0; i < b.Count; i++) {
            if (b[i] % (i + 1) != 0) return false;
        }
        return true;
    }

    static int CountGood(int idx, int[] a, List<int> cur) {
        if (idx == a.Length) {
            if (cur.Count == 0) return 0;
            return IsGood(cur) ? 1 : 0;
        }

        // skip
        int ans = CountGood(idx + 1, a, cur); 
    
        // take
        cur.Add(a[idx]);                      
        ans += CountGood(idx + 1, a, cur);
        cur.RemoveAt(cur.Count - 1);

        return ans;
    }

    static void Main() {
        int[] a = {2, 2, 1, 22, 14};
        Console.WriteLine(CountGood(0, a, new List<int>()));
    }
}
JavaScript
function isGood(b) {
    for (let i = 0; i < b.length; i++) {
        if (b[i] % (i + 1) !== 0) return false;
    }
    return true;
}

function countGood(idx, a, cur) {
    if (idx === a.length) {
        if (cur.length === 0) return 0;
        return isGood(cur) ? 1 : 0;
    }

    // skip
    let ans = countGood(idx + 1, a, cur);

    // take
    cur.push(a[idx]);
    ans += countGood(idx + 1, a, cur);
    cur.pop();

    return ans;
}

//Driver Code
const a = [2, 2, 1, 22, 14];
console.log(countGood(0, a, []));

Output
13

[Better Approach] Memoization — O(n²) Time, O(n²) Space

In this approach, we use memoization to avoid recomputing overlapping subproblems.

The DP state is defined as dp[idx][len], representing the number of good subsequences that can be formed using elements from index idx onward with current subsequence length len.

The recurrence is:

dp(idx, len) = dp(idx+1, len) + dp(idx+1, len+1)  if a[idx] % (len+1) == 0

The base case returns 1 for non-empty subsequences and 0 otherwise.


C++
#include <bits/stdc++.h>
using namespace std;

int mod = 1000000007;

int countGoodSubsequences(int idx, int len, vector<int>& arr, vector<vector<int>>& dp) {
    if (idx == arr.size())
        return (len > 0) ? 1 : 0;

    if (dp[idx][len] != -1)
        return dp[idx][len];

    // skip current element
    long long ans = countGoodSubsequences(idx + 1, len, arr, dp);

    // take current element if valid
    if (arr[idx] % (len + 1) == 0)
        ans += countGoodSubsequences(idx + 1, len + 1, arr, dp);

    return dp[idx][len] = ans % mod;
}

int main() {
    vector<int> arr = {2, 2, 1, 22, 14};
    int n = arr.size();
    vector<vector<int>> dp(n + 1, vector<int>(n + 1, -1));

    cout << countGoodSubsequences(0, 0, arr, dp);
    return 0;
}
Java
import java.util.*;

class GFG {
    static final int MOD = 1000000007;
    static int[][] dp;
    static int[] arr;

    static int countGoodSubsequences(int idx, int len)
    {
        if (idx == arr.length)
            return (len > 0) ? 1 : 0;

        if (dp[idx][len] != -1)
            return dp[idx][len];

        // skip
        long ans = countGoodSubsequences(idx + 1, len);

        if (arr[idx] % (len + 1) == 0) {

            // take
            ans += countGoodSubsequences(idx + 1, len + 1);
        }
        return dp[idx][len] = (int)(ans % MOD);
    }

    public static void main(String[] args)
    {
        arr = new int[] { 2, 2, 1, 22, 14 };
        int n = arr.length;
        dp = new int[n + 1][n + 1];

        for (int[] row : dp)
            Arrays.fill(row, -1);

        System.out.println(countGoodSubsequences(0, 0));
    }
}
Python
def countGoodSubsequences(idx, length, arr, dp):
    if idx == len(arr):
        return 1 if length > 0 else 0

    if dp[idx][length] != -1:
        return dp[idx][length]

    # skip current element
    ans = countGoodSubsequences(idx + 1, length, arr, dp)

    # take current element if valid
    if arr[idx] % (length + 1) == 0:
        ans += countGoodSubsequences(idx + 1, length + 1, arr, dp)

    dp[idx][length] = ans
    return ans


if __name__ == "__main__":
    arr = [2, 2, 1, 22, 14]
    n = len(arr)
    dp = [[-1] * (n + 1) for _ in range(n + 1)]

    print(countGoodSubsequences(0, 0, arr, dp))
C#
using System;
using System.Collections.Generic;

class Program {
    static int mod = 1000000007;
    static int[, ] dp;
    static int[] arr;

    static int CountGoodSubsequences(int idx, int len)
    {
        if (idx == arr.Length)
            return (len > 0) ? 1 : 0;

        if (dp[idx, len] != -1)
            return dp[idx, len];

        // skip
        long ans = CountGoodSubsequences(idx + 1, len);

        if (arr[idx] % (len + 1) == 0) {

            // take
            ans += CountGoodSubsequences(idx + 1, len + 1);
        }
        return dp[idx, len] = (int)(ans % mod);
    }

    static void Main()
    {
        arr = new int[] { 2, 2, 1, 22, 14 };
        int n = arr.Length;
        dp = new int[n + 1, n + 1];

        for (int i = 0; i <= n; i++)
            for (int j = 0; j <= n; j++)
                dp[i, j] = -1;

        Console.WriteLine(CountGoodSubsequences(0, 0));
    }
}
JavaScript
const mod = 1000000007;

function countGoodSubsequences(idx, len, arr, dp) {
    if (idx === arr.length)
        return len > 0 ? 1 : 0;

    if (dp[idx][len] !== -1)
        return dp[idx][len];

    // skip current element
    let ans = countGoodSubsequences(idx + 1, len, arr, dp);

    // take current element if valid
    if (arr[idx] % (len + 1) === 0)
        ans += countGoodSubsequences(idx + 1, len + 1, arr, dp);

    dp[idx][len] = ans % mod;
    return dp[idx][len];
}

//Driver Code
function main() {
    let arr = [2, 2, 1, 22, 14];
    let n = arr.length;
    let dp = Array.from({ length: n + 1 }, () => Array(n + 1).fill(-1));

    console.log(countGoodSubsequences(0, 0, arr, dp));
}

main();

Output
13

[Better Approach] Tabulation — O(n²) Time, O(n) Space

In this approach, we use bottom-up dynamic programming. Let dp[len] represent the number of good subsequences of length len. Initially, dp[0] = 1 to help build subsequences. For each element, we try to place it at a valid subsequence position len such that a[i] % len == 0. We update dp in reverse order to avoid reuse of the same element.

C++
#include <bits/stdc++.h>
using namespace std;

int countGoodSubsequences(vector<int>& arr) {
    int n = arr.size();
    const int mod = 1000000007;
    vector<long long> dp(n + 1, 0);
    dp[0] = 1;

    for (int x : arr) {
        for (int len = n; len >= 1; len--) {
            if (x % len == 0) {
                dp[len] = (dp[len] + dp[len - 1]) % mod;
            }
        }
    }

    long long ans = 0;
    for (int len = 1; len <= n; len++) ans = (ans + dp[len]) % mod;
    return ans;
}

int main() {
    vector<int> arr = {2, 2, 1, 22, 14};
    cout << countGoodSubsequences(arr);
    return 0;
}
Java
import java.util.*;

class GFG {
    static final int MOD = 1000000007;

    static int countGoodSubsequences(int[] arr) {
        int n = arr.length;
        long[] dp = new long[n + 1];
        dp[0] = 1;

        for (int x : arr) {
            for (int len = n; len >= 1; len--) {
                if (x % len == 0) {
                    dp[len] = (dp[len] + dp[len - 1]) % MOD;
                }
            }
        }

        long ans = 0;
        for (int len = 1; len <= n; len++) ans = (ans + dp[len]) % MOD;
        return (int) ans;
    }

    public static void main(String[] args) {
        int[] arr = {2, 2, 1, 22, 14};
        System.out.println(countGoodSubsequences(arr));
    }
}
Python
def countGoodSubsequences(arr):
    n = len(arr)
    mod = 1000000007
    dp = [0] * (n + 1)
    dp[0] = 1

    for x in arr:
        for length in range(n, 0, -1):
            if x % length == 0:
                dp[length] = (dp[length] + dp[length - 1]) % mod

    return sum(dp[1:]) % mod


if __name__ == "__main__":
    arr = [2, 2, 1, 22, 14]
    print(countGoodSubsequences(arr))
C#
using System;

class GFG {
    static int CountGoodSubsequences(int[] arr) {
        int n = arr.Length;
        const int mod = 1000000007;
        long[] dp = new long[n + 1];
        dp[0] = 1;

        foreach (int x in arr) {
            for (int len = n; len >= 1; len--) {
                if (x % len == 0) {
                    dp[len] = (dp[len] + dp[len - 1]) % mod;
                }
            }
        }

        long ans = 0;
        for (int len = 1; len <= n; len++) ans = (ans + dp[len]) % mod;
        return (int) ans;
    }

    static void Main() {
        int[] arr = {2, 2, 1, 22, 14};
        Console.WriteLine(CountGoodSubsequences(arr));
    }
}
JavaScript
const MOD = 1000000007;

function countGoodSubsequences(arr) {
    const n = arr.length;
    const dp = Array(n + 1).fill(0);
    dp[0] = 1;

    for (const x of arr) {
        for (let len = n; len >= 1; len--) {
            if (x % len === 0) {
                dp[len] = (dp[len] + dp[len - 1]) % MOD;
            }
        }
    }

    let ans = 0;
    for (let len = 1; len <= n; len++) ans = (ans + dp[len]) % MOD;
    return ans;
}


// Driver Code
function main() {
    const arr = [2, 2, 1, 22, 14];
    console.log(countGoodSubsequences(arr));
}

main();

Output
13


Comment