Skip to content
Related Articles

Related Articles

Count of valid arrays of size P with elements in range [1, N] having duplicates at least M distance apart

View Discussion
Improve Article
Save Article
Like Article
  • Difficulty Level : Expert
  • Last Updated : 04 Jun, 2022

Go to CDN’s CopyGiven three integers N, M and P, the task is to find the total number of valid arrays that can be created of size P having each element in range [1, N], such that the duplicates appear at least M distance apart.

Example:

Input: N = 2, M = 0, P = 3
Output: 6
Explanation: All valid arrays are: {1, 2, 1}, {1, 1, 2}, {2, 1, 1}, {2, 2, 1}, {2, 1, 2}, {1, 2, 2}.

Input: N = 2, M = 1, P = 4
Output: 2
Explanation: All valid arrays are: {1, 2, 1, 2}, {2, 1, 2, 1}

 

Approach: The problem can be solved with the help of Dynamic Programming,  

  • There are two choices possible at each index are : either we append already used element at least M distance apart, or we append a new element and decrement the count of unused characters.
  • To handle this, use recursive dynamic programming.
  • To speed up the recursive calls, use memoization so that already calculated states are not calculated again.
  • Let’s define:  dp[i][j][k] as the number of arrays till i-th position in which j unique elements are present and k be number of elements which are not used.
  • At each step there are two options:
    1. Choose previously occurred elements, j and k wouldn’t change as number of used and unused elements doesn’t change : dp[i+1][j][k]
    2. Choose element that has never been used, for this case, the number of used character will increment by 1 and the number of unused characters will decrement by 1 : dp[i+1][j+1][k-1]

dp[i][j][k] will be the summation of above two steps, represented as : 

  •  

   dp[i][j][k] = dp[i+1][j][k] + dp[i+1][j+1][k-1]

  • The final answer will be dp[0][0][N].

Below is the implementation of the above approach: 

C++




// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to calculate the total
// number of arrays
int calculate(int position, int used, int unused, int P,
              int M, vector<vector<vector<int> > >& dp)
{
    // If the size of the array is P
    if (position == P) {
        // Check if all elements are
        // used atlease once
        return unused == 0 ? 1 : 0;
    }
 
    // Check if this state is already
    // calculated
    if (dp[position][used][unused] != -1)
        return dp[position][used][unused];
 
    // Initialize the result
    int result = 0;
 
    // Use a number from the list of
    // unused numbers
    if (unused > 0) {
        // There are 'unused' number of
        // favourable choices
        result += calculate(position + 1, used + 1,
                            unused - 1, P, M, dp)
                  * unused;
    }
 
    // Use a number from already present number
    // atlease M distance back
    if (used > M) {
        // There are 'used - M' number of
        // favourable choices
        result += calculate(position + 1,
                            used, unused, P,
                            M, dp)
                  * (used - M);
    }
 
    // Store the result
    return dp[position][used][unused] = result;
}
 
// Function to solve the problem
int solve(int N, int P, int M)
{
    // Initialize DP table : dp[i][j][j]
    // i : current position/index
    // j : number of used elements
    // k : number of unused elements
    vector<vector<vector<int> > > dp(
        101,
        vector<vector<int> >(101,
                             vector<int>(101, -1)));
 
    return calculate(0, 0, N, P, M, dp);
}
// Driver Code
int main()
{
    int N = 2, M = 0, P = 3;
    cout << solve(N, P, M);
}


Java




// Java program for the above approach
import java.io.*;
class GFG
{
 
  // Function to calculate the total
  // number of arrays
  static int calculate(int position, int used, int unused, int P,
                       int M, int dp[][][])
  {
    // If the size of the array is P
    if (position == P)
    {
       
      // Check if all elements are
      // used atlease once
      return unused == 0 ? 1 : 0;
    }
 
    // Check if this state is already
    // calculated
    if (dp[position][used][unused] != -1)
      return dp[position][used][unused];
 
    // Initialize the result
    int result = 0;
 
    // Use a number from the list of
    // unused numbers
    if (unused > 0) {
      // There are 'unused' number of
      // favourable choices
      result += calculate(position + 1, used + 1,
                          unused - 1, P, M, dp)
        * unused;
    }
 
    // Use a number from already present number
    // atlease M distance back
    if (used > M)
    {
       
      // There are 'used - M' number of
      // favourable choices
      result += calculate(position + 1,
                          used, unused, P,
                          M, dp)
        * (used - M);
    }
 
    // Store the result
    return dp[position][used][unused] = result;
  }
 
  // Function to solve the problem
  static int solve(int N, int P, int M)
  {
    // Initialize DP table : dp[i][j][j]
    // i : current position/index
    // j : number of used elements
    // k : number of unused elements
    int[][][] dp = new int[101][101][101];
    for(int i = 0; i < 101; i++)
    {
      for(int j = 0; j < 101; j++)
        for(int k = 0; k < 101; k++)
          dp[i][j][k] = -1;
    }
    return calculate(0, 0, N, P, M, dp);
  }
 
  // Driver Code
  public static void main(String[] args)
  {
    int N = 2, M = 0, P = 3;
    System.out.println(solve(N, P, M));
  }
}
 
// This code is contributed by dwivediyash


Python3




# Python 3 program for the above approach
 
# Function to calculate the total
# number of arrays
def calculate(position, used, unused, P, M, dp):
   
    # If the size of the array is P
    if (position == P):
       
        # Check if all elements are
        # used atlease once
        if unused == 0:
          return 1
        else:
          return 0
 
    # Check if this state is already
    # calculated
    if (dp[position][used][unused] != -1):
        return dp[position][used][unused]
 
    # Initialize the result
    result = 0
 
    # Use a number from the list of
    # unused numbers
    if (unused > 0):
       
        # There are 'unused' number of
        # favourable choices
        result += calculate(position + 1, used + 1,unused - 1, P, M, dp)* unused
 
    # Use a number from already present number
    # atlease M distance back
    if (used > M):
       
        # There are 'used - M' number of
        # favourable choices
        result += calculate(position + 1,used, unused, P,M, dp)* (used - M)
    dp[position][used][unused] = result
 
    # Store the result
    return dp[position][used][unused]
 
# Function to solve the problem
def solve(N, P, M):
   
    # Initialize DP table : dp[i][j][j]
    # i : current position/index
    # j : number of used elements
    # k : number of unused elements
    dp = [[[-1 for i in range(101)] for i in range(101)] for j in range(101)]
 
    return calculate(0, 0, N, P, M, dp)
 
# Driver Code
if __name__ == '__main__':
    N = 2
    M = 0
    P = 3
    print(solve(N, P, M))
     
    # This code is contributed by SURENDRA_GANGWAR.


C#




// C# program for the above approach
using System;
 
public class GFG
{
 
  // Function to calculate the total
  // number of arrays
  static int calculate(int position, int used, int unused, int P,
                       int M, int [,,]dp)
  {
     
    // If the size of the array is P
    if (position == P)
    {
       
      // Check if all elements are
      // used atlease once
      return unused == 0 ? 1 : 0;    
    }
 
    // Check if this state is already
    // calculated
    if (dp[position,used,unused] != -1)
      return dp[position,used,unused];
 
    // Initialize the result
    int result = 0;
 
    // Use a number from the list of
    // unused numbers
    if (unused > 0)
    {
       
      // There are 'unused' number of
      // favourable choices
      result += calculate(position + 1, used + 1,
                          unused - 1, P, M, dp)
        * unused;
    }
 
    // Use a number from already present number
    // atlease M distance back
    if (used > M)
    {
       
      // There are 'used - M' number of
      // favourable choices
      result += calculate(position + 1,
                          used, unused, P,
                          M, dp)
        * (used - M);
    }
 
    // Store the result
    return dp[position,used,unused] = result;
  }
 
  // Function to solve the problem
  static int solve(int N, int P, int M)
  {
     
    // Initialize DP table : dp[i,j,j]
    // i : current position/index
    // j : number of used elements
    // k : number of unused elements
    int[,,] dp = new int[101,101,101];
    for(int i = 0; i < 101; i++)
    {
      for(int j = 0; j < 101; j++)
        for(int k = 0; k < 101; k++)
          dp[i, j, k] = -1;
    }
    return calculate(0, 0, N, P, M, dp);
  }
 
  // Driver Code
  public static void Main(String[] args)
  {
    int N = 2, M = 0, P = 3;
    Console.WriteLine(solve(N, P, M));
  }
}
 
// This code is contributed by shikhasingrajput


Javascript




<script>
        // JavaScript Program to implement
        // the above approach
 
        // Function to calculate the total
        // number of arrays
        function calculate(position, used, unused, P,
            M, dp)
       {
        
            // If the size of the array is P
            if (position == P)
            {
             
                // Check if all elements are
                // used atlease once
                return unused == 0 ? 1 : 0;
            }
 
            // Check if this state is already
            // calculated
            if (dp[position][used][unused] != -1)
                return dp[position][used][unused];
 
            // Initialize the result
            let result = 0;
 
            // Use a number from the list of
            // unused numbers
            if (unused > 0)
            {
             
                // There are 'unused' number of
                // favourable choices
                result += calculate(position + 1, used + 1,
                    unused - 1, P, M, dp)
                    * unused;
            }
 
            // Use a number from already present number
            // atlease M distance back
            if (used > M)
            {
             
                // There are 'used - M' number of
                // favourable choices
                result += calculate(position + 1,
                    used, unused, P,
                    M, dp)
                    * (used - M);
            }
 
            // Store the result
            return dp[position][used][unused] = result;
        }
 
        // Function to solve the problem
        function solve(N, P, M)
        {
         
            // Initialize DP table : dp[i][j][j]
            // i : current position/index
            // j : number of used elements
            // k : number of unused elements
            var dp = new Array(101);
 
            // create 2D
            for (let i = 0; i < dp.length; i++) {
                dp[i] = new Array(101).fill(-1);
            }
 
            // create 3D
            for (let i = 0; i < dp.length; i++) {
                for (let j = 0; j < dp[0].length; j++) {
                    dp[i][j] = new Array(101).fill(-1);
                }
            }
            return calculate(0, 0, N, P, M, dp);
        }
         
        // Driver Code
        let N = 2, M = 0, P = 3;
        document.write(solve(N, P, M));
 
// This code is contributed by Potta Lokesh
 
    </script>


 
 

Output

6

 

Time Complexity: O(N*M*P) (Because of three dependent variables)

 

Auxiliary Space: O(N*M*P) (Size of the DP matrix)

 


My Personal Notes arrow_drop_up
Recommended Articles
Page :

Start Your Coding Journey Now!