Count of non-decreasing Arrays
Last Updated :
01 Oct, 2023
Given two arrays A[] and B[] both of size N, the task is to count the number of non-decreasing arrays C[] of size N such that for (1 ≤ i ≤ N) A[i] ≤ C[i] ≤ B[i] holds true.
Array is non-decreasing if C[i] ≤ C[i + 1] holds for every i (1-based indexing) such that (1 ≤ i ≤ N – 1).
Examples:
Input: A[] = {1, 1}, B[] = {2, 3}
Output: 5
Explanation: {1, 1}, {1, 2}, {1, 3}, {2, 2} and {2, 3} are the possible arrays that follow above conditions
Input: A[] = {2, 2, 2}, B[] = {2, 2, 2}
Output: 1
Explanation: {2, 2, 2} is the only array possible that follows the above conditions.
Naive approach: The Brute Force to solve the problem is as follows:
Naive Dynamic Programming can be written for this problem
- dp[i][j] represents the maximum number of arrays formed of size i and j being the last element chosen.
- Recurrence relation: dp[i][j] = summation of dp[i – 1][k] for k from 1 to Cmax ( Cmax is the maximum value possible in array C[] )
Time Complexity: O(N3)
Auxiliary Space: O(N2)
Efficient Approach: The above approach can be optimized based on the following idea:
The above DP can be optimized with Prefix sum performing on DP values.
- dp[i][j] = summation of dp[i – 1][k] where k is from 1 to Cmax
- This calculation can be avoided as this is calculating for each j from 1 to j which takes O(N2).
- Prefix sum used in order to avoid these calculations and reduce the time complexity by factor O(N).
Follow the steps below to solve the problem:
- Declare dp[N][Cmax] which has all elements zero initially.
- Base case dp[0][0] = 1.
- Iterate for each 0 to N – 1 on each iteration take prefix sum dp[i][j] = dp[i – 1][j] + dp[i][j – 1];
- Make values zero that are useless by running a loop from 0 to A[i] and B[i] + 1 to Cmax to avoid calculation errors on the next state.
- Declare variable ANS and initialize it with value 0.
- add values for each k from 0 to Cmax of dp[N][k] and print the answer.
Below is the implementation of the above approach.
C++
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
void countNonDecreasingArrays( int A[], int B[], int N)
{
vector<vector< int > > dp(N + 1, vector< int >(3001, 0));
dp[0][0] = 1;
for ( int i = 0; i < N; i++) {
dp[i + 1][0] = dp[i][0];
for ( int j = 1; j <= 3000; j++) {
dp[i + 1][j]
= (dp[i + 1][j - 1] + dp[i][j]) % MOD;
}
for ( int j = 0; j < A[i]; j++) {
dp[i + 1][j] = 0;
}
for ( int j = B[i] + 1; j <= 3000; j++) {
dp[i + 1][j] = 0;
}
}
int long long ans = 0;
for ( int i = 0; i <= 3000; i++) {
ans += dp[N][i];
}
cout << ans % MOD << endl;
}
int main()
{
int A[] = { 1, 1 }, B[] = { 2, 3 };
int N = sizeof (A) / sizeof (A[0]);
countNonDecreasingArrays(A, B, N);
int A1[] = { 2, 2, 2 }, B1[] = { 2, 2, 2 };
int N1 = sizeof (A1) / sizeof (A1[0]);
countNonDecreasingArrays(A1, B1, N1);
return 0;
}
|
Java
import java.io.*;
class GFG {
static int MOD = 1000000007 ;
public static void
countNonDecreasingArrays( int A[], int B[], int N)
{
int dp[][] = new int [N + 1 ][ 3001 ];
dp[ 0 ][ 0 ] = 1 ;
for ( int i = 0 ; i < N; i++) {
dp[i + 1 ][ 0 ] = dp[i][ 0 ];
for ( int j = 1 ; j <= 3000 ; j++) {
dp[i + 1 ][j]
= (dp[i + 1 ][j - 1 ] + dp[i][j]) % MOD;
}
for ( int j = 0 ; j < A[i]; j++) {
dp[i + 1 ][j] = 0 ;
}
for ( int j = B[i] + 1 ; j <= 3000 ; j++) {
dp[i + 1 ][j] = 0 ;
}
}
long ans = 0 ;
for ( int i = 0 ; i <= 3000 ; i++) {
ans += dp[N][i];
}
System.out.println(ans % MOD);
}
public static void main(String[] args)
{
int A[] = { 1 , 1 };
int B[] = { 2 , 3 };
int N = A.length;
countNonDecreasingArrays(A, B, N);
int A1[] = { 2 , 2 , 2 };
int B1[] = { 2 , 2 , 2 };
int N1 = A1.length;
countNonDecreasingArrays(A1, B1, N1);
}
}
|
Python3
MOD = 1000000007
def countNonDecreasingArrays(A, B, N):
dp = [[ 0 ] * 3001 for _ in range (N + 1 )]
dp[ 0 ][ 0 ] = 1
for i in range (N):
dp[i + 1 ][ 0 ] = dp[i][ 0 ]
for j in range ( 1 , 3001 ):
dp[i + 1 ][j] = (dp[i + 1 ][j - 1 ] + dp[i][j]) % MOD
for j in range (A[i]):
dp[i + 1 ][j] = 0
for j in range (B[i] + 1 , 3001 ):
dp[i + 1 ][j] = 0
ans = 0
for i in range ( 3001 ):
ans + = dp[N][i]
print (ans % MOD)
A = [ 1 , 1 ]
B = [ 2 , 3 ]
N = len (A)
countNonDecreasingArrays(A, B, N)
A1 = [ 2 , 2 , 2 ]
B1 = [ 2 , 2 , 2 ]
N1 = len (A1)
countNonDecreasingArrays(A1, B1, N1)
|
C#
using System;
class GFG {
static int MOD = 1000000007;
public static void
countNonDecreasingArrays( int [] A, int [] B, int N)
{
int [,] dp = new int [N + 1,3001];
dp[0,0] = 1;
for ( int i = 0; i < N; i++) {
dp[i + 1,0] = dp[i,0];
for ( int j = 1; j <= 3000; j++) {
dp[i + 1,j]
= (dp[i + 1,j - 1] + dp[i,j]) % MOD;
}
for ( int j = 0; j < A[i]; j++) {
dp[i + 1,j] = 0;
}
for ( int j = B[i] + 1; j <= 3000; j++) {
dp[i + 1,j] = 0;
}
}
long ans = 0;
for ( int i = 0; i <= 3000; i++) {
ans += dp[N,i];
}
Console.WriteLine(ans % MOD);
}
public static void Main()
{
int [] A = { 1, 1 };
int [] B = { 2, 3 };
int N = A.Length;
countNonDecreasingArrays(A, B, N);
int [] A1 = { 2, 2, 2 };
int [] B1 = { 2, 2, 2 };
int N1 = A1.Length;
countNonDecreasingArrays(A1, B1, N1);
}
}
|
Javascript
let MOD = 1e9 + 7;
function countNonDecreasingArrays( A, B, N)
{
let dp= new Array(N+1);
for (let i=0; i<N+1; i++)
dp[i]= new Array(3001).fill(0);
dp[0][0] = 1;
for (let i = 0; i < N; i++) {
dp[i + 1][0] = dp[i][0];
for (let j = 1; j <= 3000; j++) {
dp[i + 1][j]
= (dp[i + 1][j - 1] + dp[i][j]) % MOD;
}
for (let j = 0; j < A[i]; j++) {
dp[i + 1][j] = 0;
}
for (let j = B[i] + 1; j <= 3000; j++) {
dp[i + 1][j] = 0;
}
}
let ans = 0;
for (let i = 0; i <= 3000; i++) {
ans += dp[N][i];
}
document.write(ans % MOD);
}
let A = [ 1, 1 ], B = [ 2, 3 ];
let N = A.length;
countNonDecreasingArrays(A, B, N);
document.write( "<br>" );
let A1 = [ 2, 2, 2 ], B1 = [ 2, 2, 2 ];
let N1= A1.length;
countNonDecreasingArrays(A1, B1, N1);
|
Time Complexity: O(N2)
Auxiliary Space: O(N2)
Another Approach : Using Recursion + memoization
In this approach we solve this problem by calling the function again and again and compute the subproblems to find the solution of actual problem
Implementation steps :
- Create a 2d matrix says dp and initialize it with -1.
- Now recursively call the function for its sub-problems and check in dp whether it is previously computed or not.
- If it is not computed then dp store -1 and we have to compute the value the store the computed value in dp.
- If dp not store -1 then we can say that the current value is previously computed so we will return that value.
- At last we return the final answer.
Implementation :
C++
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
long long countArrays( int A[], int B[], int N, int idx, int prev, vector<vector< long long >>& dp) {
if (idx == N) {
return 1;
}
if (dp[idx][prev] != -1) {
return dp[idx][prev];
}
long long ans = 0;
for ( int i = A[idx]; i <= B[idx]; i++) {
if (i >= prev) {
ans += countArrays(A, B, N, idx+1, i, dp);
ans %= MOD;
}
}
dp[idx][prev] = ans;
return ans;
}
void countNonDecreasingArrays( int A[], int B[], int N) {
vector<vector< long long >> dp(N, vector< long long >(3001, -1));
long long ans = countArrays(A, B, N, 0, 0, dp);
cout << ans << endl;
}
int main() {
int A[] = { 1, 1 }, B[] = { 2, 3 };
int N = sizeof (A) / sizeof (A[0]);
countNonDecreasingArrays(A, B, N);
int A1[] = { 2, 2, 2 }, B1[] = { 2, 2, 2 };
int N1 = sizeof (A1) / sizeof (A1[0]);
countNonDecreasingArrays(A1, B1, N1);
return 0;
}
|
Java
import java.util.*;
public class Main {
static final int MOD = 1000000007 ;
static long countArrays( int [] A, int [] B, int N, int idx, int prev, long [][] dp) {
if (idx == N) {
return 1 ;
}
if (dp[idx][prev] != - 1 ) {
return dp[idx][prev];
}
long ans = 0 ;
for ( int i = A[idx]; i <= B[idx]; i++) {
if (i >= prev) {
ans += countArrays(A, B, N, idx+ 1 , i, dp);
ans %= MOD;
}
}
dp[idx][prev] = ans;
return ans;
}
static void countNonDecreasingArrays( int [] A, int [] B, int N) {
long [][] dp = new long [N][ 3001 ];
for ( long [] row : dp) {
Arrays.fill(row, - 1 );
}
long ans = countArrays(A, B, N, 0 , 0 , dp);
System.out.println(ans);
}
public static void main(String[] args) {
int [] A = { 1 , 1 }, B = { 2 , 3 };
int N = A.length;
countNonDecreasingArrays(A, B, N);
int [] A1 = { 2 , 2 , 2 }, B1 = { 2 , 2 , 2 };
int N1 = A1.length;
countNonDecreasingArrays(A1, B1, N1);
}
}
|
Python
MOD = 10 * * 9 + 7
def countArrays(A, B, N, idx, prev, dp):
if idx = = N:
return 1
if dp[idx][prev] ! = - 1 :
return dp[idx][prev]
ans = 0
for i in range (A[idx], B[idx] + 1 ):
if i > = prev:
ans + = countArrays(A, B, N, idx + 1 , i, dp)
ans % = MOD
dp[idx][prev] = ans
return ans
def countNonDecreasingArrays(A, B, N):
dp = [[ - 1 for j in range ( 3001 )] for i in range (N)]
ans = countArrays(A, B, N, 0 , 0 , dp)
print (ans)
if __name__ = = '__main__' :
A = [ 1 , 1 ]
B = [ 2 , 3 ]
N = len (A)
countNonDecreasingArrays(A, B, N)
A1 = [ 2 , 2 , 2 ]
B1 = [ 2 , 2 , 2 ]
N1 = len (A1)
countNonDecreasingArrays(A1, B1, N1)
|
C#
using System;
using System.Collections.Generic;
public class Program {
const int MOD = 1000000007;
static long CountArrays( int [] A, int [] B, int N, int idx, int prev, long ?[,] dp) {
if (idx == N) {
return 1;
}
if (dp[idx, prev] != null ) {
return dp[idx, prev].Value;
}
long ans = 0;
for ( int i = A[idx]; i <= B[idx]; i++) {
if (i >= prev) {
ans += CountArrays(A, B, N, idx + 1, i, dp);
ans %= MOD;
}
}
dp[idx, prev] = ans;
return ans;
}
static void CountNonDecreasingArrays( int [] A, int [] B, int N) {
long ?[,] dp = new long ?[N, 3001];
for ( int i = 0; i < N; i++) {
for ( int j = 0; j < 3001; j++) {
dp[i, j] = null ;
}
}
long ans = CountArrays(A, B, N, 0, 0, dp);
Console.WriteLine(ans);
}
public static void Main() {
int [] A = { 1, 1 }, B = { 2, 3 };
int N = A.Length;
CountNonDecreasingArrays(A, B, N);
int [] A1 = { 2, 2, 2 }, B1 = { 2, 2, 2 };
int N1 = A1.Length;
CountNonDecreasingArrays(A1, B1, N1);
}
}
|
Javascript
function countArrays(A, B, N, idx, prev, dp) {
if (idx == N) {
return 1;
}
if (dp[idx][prev] !== -1) {
return dp[idx][prev];
}
let ans = 0;
for (let i = A[idx]; i <= B[idx]; i++) {
if (i >= prev) {
ans += countArrays(A, B, N, idx + 1, i, dp);
ans %= 1000000007;
}
}
dp[idx][prev] = ans;
return ans;
}
function countNonDecreasingArrays(A, B, N) {
let dp = Array.from(Array(N), () => new Array(3001).fill(-1));
let ans = countArrays(A, B, N, 0, 0, dp);
console.log(ans);
}
let A = [1, 1];
let B = [2, 3];
let N = A.length;
countNonDecreasingArrays(A, B, N);
let A1 = [2, 2, 2];
let B1 = [2, 2, 2];
let N1 = A1.length;
countNonDecreasingArrays(A1, B1, N1);
|
Time Complexity: O(N2)
Auxiliary Space: O(N2)
Efficient approach : Space optimization
In previous approach the current value dp[i][j] is only depend upon the current and previous row values of DP. So to optimize the space complexity we use a single 1D array to store the computations.
Implementation:
C++
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
void countNonDecreasingArrays( int A[], int B[], int N)
{
vector< int > dp(3001, 0);
dp[0] = 1;
for ( int i = 0; i < N; i++) {
for ( int j = 1; j <= 3000; j++) {
dp[j] = (dp[j - 1] + dp[j]) % MOD;
}
for ( int j = 0; j < A[i]; j++) {
dp[j] = 0;
}
for ( int j = B[i] + 1; j <= 3000; j++) {
dp[j] = 0;
}
}
int long long ans = 0;
for ( int i = 0; i <= 3000; i++) {
ans += dp[i];
}
cout << ans % MOD << endl;
}
int main()
{
int A[] = { 1, 1 }, B[] = { 2, 3 };
int N = sizeof (A) / sizeof (A[0]);
countNonDecreasingArrays(A, B, N);
int A1[] = { 2, 2, 2 }, B1[] = { 2, 2, 2 };
int N1 = sizeof (A1) / sizeof (A1[0]);
countNonDecreasingArrays(A1, B1, N1);
return 0;
}
|
Java
import java.util.Arrays;
public class CountNonDecreasingArrays {
static final int MOD = 1000000007 ;
static void countNonDecreasingArrays( int [] A, int [] B, int N) {
int [] dp = new int [ 3001 ];
dp[ 0 ] = 1 ;
for ( int i = 0 ; i < N; i++) {
for ( int j = 1 ; j <= 3000 ; j++) {
dp[j] = (dp[j - 1 ] + dp[j]) % MOD;
}
for ( int j = 0 ; j < A[i]; j++) {
dp[j] = 0 ;
}
for ( int j = B[i] + 1 ; j <= 3000 ; j++) {
dp[j] = 0 ;
}
}
long ans = 0 ;
for ( int i = 0 ; i <= 3000 ; i++) {
ans = (ans + dp[i]) % MOD;
}
System.out.println(ans);
}
public static void main(String[] args) {
int [] A = { 1 , 1 };
int [] B = { 2 , 3 };
int N = A.length;
countNonDecreasingArrays(A, B, N);
int [] A1 = { 2 , 2 , 2 };
int [] B1 = { 2 , 2 , 2 };
int N1 = A1.length;
countNonDecreasingArrays(A1, B1, N1);
}
}
|
Python3
MOD = 10 * * 9 + 7
def countNonDecreasingArrays(A, B):
dp = [ 0 ] * 3001
dp[ 0 ] = 1
for i in range ( len (A)):
for j in range ( 1 , 3001 ):
dp[j] = (dp[j - 1 ] + dp[j]) % MOD
for j in range (A[i]):
dp[j] = 0
for j in range (B[i] + 1 , 3001 ):
dp[j] = 0
ans = sum (dp) % MOD
print (ans)
if __name__ = = "__main__" :
A = [ 1 , 1 ]
B = [ 2 , 3 ]
countNonDecreasingArrays(A, B)
A1 = [ 2 , 2 , 2 ]
B1 = [ 2 , 2 , 2 ]
countNonDecreasingArrays(A1, B1)
|
C#
using System;
using System.Collections.Generic;
namespace NonDecreasingArrays {
class Program {
const int MOD = 1000000007;
static void CountNonDecreasingArrays( int [] A, int [] B,
int N)
{
List< int > dp = new List< int >( new int [3001]);
dp[0] = 1;
for ( int i = 0; i < N; i++) {
for ( int j = 1; j <= 3000; j++) {
dp[j] = (dp[j - 1] + dp[j]) % MOD;
}
for ( int j = 0; j < A[i]; j++) {
dp[j] = 0;
}
for ( int j = B[i] + 1; j <= 3000; j++) {
dp[j] = 0;
}
}
long ans = 0;
for ( int i = 0; i <= 3000; i++) {
ans += dp[i];
}
Console.WriteLine(ans % MOD);
}
static void Main( string [] args)
{
int [] A = { 1, 1 };
int [] B = { 2, 3 };
int N = A.Length;
CountNonDecreasingArrays(A, B, N);
int [] A1 = { 2, 2, 2 };
int [] B1 = { 2, 2, 2 };
int N1 = A1.Length;
CountNonDecreasingArrays(A1, B1, N1);
}
}
}
|
Javascript
function countNonDecreasingArrays(A, B, N) {
const MOD = 1e9 + 7;
let dp = new Array(3001).fill(0);
dp[0] = 1;
for (let i = 0; i < N; i++) {
for (let j = 1; j <= 3000; j++) {
dp[j] = (dp[j - 1] + dp[j]) % MOD;
}
for (let j = 0; j < A[i]; j++) {
dp[j] = 0;
}
for (let j = B[i] + 1; j <= 3000; j++) {
dp[j] = 0;
}
}
let ans = 0;
for (let i = 0; i <= 3000; i++) {
ans += dp[i];
}
console.log(ans % MOD);
}
let A = [1, 1];
let B = [2, 3];
let N = A.length;
countNonDecreasingArrays(A, B, N);
let A1 = [2, 2, 2];
let B1 = [2, 2, 2];
let N1 = A1.length;
countNonDecreasingArrays(A1, B1, N1);
|
Time Complexity: O(N*3001)
Auxiliary Space: O(3001)
Related Articles:
Share your thoughts in the comments
Please Login to comment...