Count possible N-digit numbers such that each digit does not appear more than given number of times consecutively

• Difficulty Level : Easy
• Last Updated : 05 Oct, 2021

Given an integer N and an array maxDigit[], the task is to count all the distinct N-digit numbers such that digit i does not appear more than maxDigit[i] times. Since the count can be very large, print it modulo 109 + 7.

Examples:

Input: N = 2, maxDigit[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
Output: 90
Explanation:
Any digit can’t appear more than once consecutively. Therefore, numbers [00, 11, 22, 33, 44, 55, 66, 77, 88, 99] are invalid.
Hence, the total numbers without any restrictions are 10×10 = 100.
Therefore, the count is 100 – 10 = 90.

Input: N = 3, maxDigit[] = {2, 1, 1, 1, 1, 2, 1, 1, 1, 2}
Output: 864

Naive Approach: The simplest approach is to iterate over all the N-digit numbers and count those numbers that satisfy the given conditions. After checking all the numbers, print the total count modulo 109 + 7

Time Complexity: O(N*10N)
Auxiliary Space: O(1)

Efficient Approach: To optimize the above approach, the idea is to use the concept of Digit Dynamic Programming. The DP states for this problem are explained as follows:

• In Digit-DP, the idea is to build a number from left to right by placing a digit [0, 9] at every position. So, to keep track of the current position, it is required to have a position state. This state will have possible values from 0 to (N – 1).
• According to the question, a digit i can’t appear more than maxDigit[i] consecutive times, therefore keep track of the previously filled digit. So, a state previous is required. This state will have possible values from 0 to 9.
• A state count is required which will provide the number of times a digit can appear consecutively. This state will have possible values from 1 to maxDigit[i].

Follow the steps below to solve this problem:

• The first position can have any digit without any restrictions.
• From the second position and onwards, keep a track of the previously filled digit and its given count up to which it can appear consecutively.
• If the same digit appears on the next position, then decrement its count and if this count becomes zero, simply ignore this digit in the next recursive call.
• If a different digit appears on the next position, then update its count according to the given value in maxDigit[].
• At each of the above recursive calls when the resultant number is generated then increment the count for that number.
• After the above steps, print the value of the total count as the result.

Below is the implementation of the above approach:

C++

 `// C++ program for the above approach` `#include ` `using` `namespace` `std;`   `// Macros for modulus` `#define MOD 1000000007`   `// DP array for memoization` `int` `dp[5005][12][12];`   `// Utility function to count N digit` `// numbers with digit i not appearing` `// more than max_digit[i] consecutively` `int` `findCountUtil(``int` `N, ``int` `maxDigit[],` `                  ``int` `position = 0,` `                  ``int` `previous = 0,` `                  ``int` `count = 1)` `{` `  `  `    ``// If number with N digits` `    ``// is generated` `    ``if` `(position == N) {` `        ``return` `1;` `    ``}`   `    ``// Create a reference variable` `    ``int``& ans = dp[position][previous][count];`   `    ``// Check if the current state is` `    ``// already computed before` `    ``if` `(ans != -1) {` `        ``return` `ans;` `    ``}`   `    ``// Initialize ans as zero` `    ``ans = 0;`   `    ``for` `(``int` `i = 0; i <= 9; ++i) {`   `        ``// Check if count of previous` `        ``// digit has reached zero or not` `        ``if` `(count == 0 && previous != i) {`   `            ``// Fill current position` `            ``// only with digits that` `            ``// are unequal to previous digit` `            ``ans = (ans` `                   ``+ (findCountUtil(N, maxDigit,` `                                    ``position + 1, i,` `                                    ``maxDigit[i] - 1))` `                         ``% MOD)` `                  ``% MOD;` `        ``}`   `        ``else` `if` `(count != 0) {`   `            ``// If by placing the same digit` `            ``// as previous on the current` `            ``// position, decrement count by 1`   `            ``// Else set the value of count` `            ``// for this new digit` `            ``// accordingly from max_digit[]` `            ``ans = (ans` `                   ``+ (findCountUtil(` `                         ``N, maxDigit, position + 1, i,` `                         ``(previous == i && position != 0)` `                             ``? count - 1` `                             ``: maxDigit[i] - 1))` `                         ``% MOD)` `                  ``% MOD;` `        ``}` `    ``}` `    ``return` `ans;` `}`   `// Function to count N digit numbers` `// with digit i not appearing more` `// than max_digit[i] consecutive times` `void` `findCount(``int` `N, ``int` `maxDigit[])` `{` `  `  `    ``// Stores the final count` `    ``int` `ans = findCountUtil(N, maxDigit);`   `    ``// Print the total count` `    ``cout << ans;` `}`   `// Driver Code` `int` `main()` `{` `    ``int` `N = 2;` `    ``int` `maxDigit[10] = { 1, 1, 1, 1, 1,` `                         ``1, 1, 1, 1, 1 };`   `    ``// Initialize the dp array with -1` `    ``memset``(dp, -1, ``sizeof``(dp));`   `    ``// Function Call` `    ``findCount(N, maxDigit);` `    ``return` `0;` `}`

Java

 `// Java program for the above approach  ` `import` `java.util.*;`   `class` `GFG{` `        `  `// Macros for modulus` `static` `int` `MOD = ``1000000007``;`   `// DP array for memoization` `static` `int` `dp[][][] = ``new` `int``[``5005``][``12``][``12``];`   `// Utility function to count N digit` `// numbers with digit i not appearing` `// more than max_digit[i] consecutively` `static` `int` `findCountUtil(``int` `N, ``int` `maxDigit[], ` `                         ``int` `position, ` `                         ``int` `previous, ` `                         ``int` `count)` `{` `    `  `    ``// If number with N digits` `    ``// is generated` `    ``if` `(position == N) ` `    ``{` `        ``return` `1``;` `    ``}`   `    ``// Create a reference variable` `    ``int` `ans = dp[position][previous][count];`   `    ``// Check if the current state is` `    ``// already computed before` `    ``if` `(ans != -``1``) ` `    ``{` `        ``return` `ans;` `    ``}`   `    ``// Initialize ans as zero` `    ``ans = ``0``;`   `    ``for``(``int` `i = ``0``; i <= ``9``; ++i) ` `    ``{` `        `  `        ``// Check if count of previous` `        ``// digit has reached zero or not` `        ``if` `(count == ``0` `&& previous != i)` `        ``{` `            `  `            ``// Fill current position` `            ``// only with digits that` `            ``// are unequal to previous digit` `            ``ans = (ans + (findCountUtil(` `                  ``N, maxDigit, position + ``1``, i,` `                  ``maxDigit[i] - ``1``)) % MOD) % MOD;` `        ``}`   `        ``else` `if` `(count != ``0``) ` `        ``{` `            `  `            ``// If by placing the same digit` `            ``// as previous on the current` `            ``// position, decrement count by 1`   `            ``// Else set the value of count` `            ``// for this new digit` `            ``// accordingly from max_digit[]` `            ``ans = (ans + (findCountUtil(` `                  ``N, maxDigit, position + ``1``, i,` `                  ``(previous == i && position != ``0``) ? ` `                  ``count - ``1` `: maxDigit[i] - ``1``)) % MOD) % MOD;` `        ``}` `    ``}` `    `  `    ``return` `ans;` `}`   `// Function to count N digit numbers` `// with digit i not appearing more` `// than max_digit[i] consecutive times` `static` `void` `findCount(``int` `N, ``int` `maxDigit[])` `{` `    ``int` `position = ``0``; ` `    ``int` `previous = ``0``; ` `    ``int` `count = ``1``;` `    `  `    ``// Stores the final count` `    ``int` `ans = findCountUtil(N, maxDigit, position,` `                            ``previous, count);`   `    ``// Print the total count` `    ``System.out.println(ans);` `}`   `// Driver Code    ` `public` `static` `void` `main (String[] args)    ` `{    ` `    ``int` `N = ``2``;` `    ``int``[] maxDigit = { ``1``, ``1``, ``1``, ``1``, ``1``,` `                       ``1``, ``1``, ``1``, ``1``, ``1` `};`   `    ``// Initialize the dp array with -1` `    ``// Fill each row with -1.  ` `    ``for``(``int``[][] row : dp) ` `    ``{ ` `        ``for``(``int``[] rowColumn : row)` `        ``{ ` `            ``Arrays.fill(rowColumn, -``1``); ` `        ``} ` `    ``}` `    `  `    ``// Function Call` `    ``findCount(N, maxDigit);` `}` `}`   `// This code is contributed by susmitakundugoaldanga`

Python3

 `# Python3 program for the above approach` `# Macros for modulus`   `# DP array for memoization` `dp ``=` `[[[ ``-``1` `for` `i ``in` `range``(``5005``)] ``for` `i ``in` `range``(``12``) ] ``for` `i ``in` `range``(``12``)]`   `# Utility function to count N digit` `# numbers with digit i not appearing` `# more than max_digit[i] consecutively` `def` `findCountUtil(N, maxDigit, position ,previous ,count):` `    ``global` `dp` `    `  `    ``# If number with N digits` `    ``# is generated` `    ``if` `(position ``=``=` `N):` `        ``return` `1`   `    ``# Create a reference variable` `    ``ans ``=` `dp[position][previous][count]`   `    ``# Check if the current state is` `    ``# already computed before` `    ``if` `(ans !``=` `-``1``):` `        ``return` `ans`   `    ``# Initialize ans as zero` `    ``ans ``=` `0` `    ``for` `i ``in` `range``(``10``):`   `        ``# Check if count of previous` `        ``# digit has reached zero or not` `        ``if` `(count ``=``=` `0` `and` `previous !``=` `i):`   `            ``# Fill current position` `            ``# only with digits that` `            ``# are unequal to previous digit` `            ``ans ``=` `(ans ``+` `(findCountUtil(N, maxDigit, position ``+` `1``, i, maxDigit[i] ``-` `1``)) ``%` `1000000007``)``%` `1000000007` `        ``elif` `(count !``=` `0``):`   `            ``# If by placing the same digit` `            ``# as previous on the current` `            ``# position, decrement count by 1`   `            ``# Else set the value of count` `            ``# for this new digit` `            ``# accordingly from max_digit[]` `            ``ans ``=` `(ans ``+` `(findCountUtil(N, maxDigit, position ``+` `1``, i, count ``-` `1` `if` `(previous ``=``=` `i ``and` `position !``=` `0``) ``else` `maxDigit[i] ``-` `1``)) ``%` `1000000007``)``%` `1000000007`   `    ``dp[position][previous][count] ``=` `ans` `    ``return` `ans`   `# Function to count N digit numbers` `# with digit i not appearing more` `# than max_digit[i] consecutive times` `def` `findCount(N, maxDigit):` `    `  `    ``# Stores the final count` `    ``ans ``=` `findCountUtil(N, maxDigit, ``0``, ``0``, ``1``)`   `    ``# Print the total count` `    ``print` `(ans)`   `# Driver Code` `if` `__name__ ``=``=` `'__main__'``:` `    ``N ``=` `2` `    ``maxDigit ``=` `[``1``, ``1``, ``1``, ``1``, ``1``,``1``, ``1``, ``1``, ``1``, ``1``]`   `    ``# Function Call` `    ``findCount(N, maxDigit)`   `    ``# This code is contributed by mohit kumar 29`

C#

 `// C# program for the above approach  ` `using` `System;` `using` `System.Collections.Generic;`     `using` `System;` `using` `System.Collections.Generic;` `public` `class` `GFG{` `        `  `// Macros for modulus` `static` `int` `MOD = 1000000007;`   `// DP array for memoization` `static` `int` `[,,]dp = ``new` `int``[5005, 12, 12];`   `// Utility function to count N digit` `// numbers with digit i not appearing` `// more than max_digit[i] consecutively` `static` `int` `findCountUtil(``int` `N, ``int` `[]maxDigit, ` `                         ``int` `position, ` `                         ``int` `previous, ` `                         ``int` `count)` `{` `    `  `    ``// If number with N digits` `    ``// is generated` `    ``if` `(position == N) ` `    ``{` `        ``return` `1;` `    ``}`   `    ``// Create a reference variable` `    ``int` `ans = dp[position, previous, count];`   `    ``// Check if the current state is` `    ``// already computed before` `    ``if` `(ans != -1) ` `    ``{` `        ``return` `ans;` `    ``}`   `    ``// Initialize ans as zero` `    ``ans = 0;`   `    ``for``(``int` `i = 0; i <= 9; ++i) ` `    ``{` `        `  `        ``// Check if count of previous` `        ``// digit has reached zero or not` `        ``if` `(count == 0 && previous != i)` `        ``{` `            `  `            ``// Fill current position` `            ``// only with digits that` `            ``// are unequal to previous digit` `            ``ans = (ans + (findCountUtil(` `                  ``N, maxDigit, position + 1, i,` `                  ``maxDigit[i] - 1)) % MOD) % MOD;` `        ``}`   `        ``else` `if` `(count != 0) ` `        ``{` `            `  `            ``// If by placing the same digit` `            ``// as previous on the current` `            ``// position, decrement count by 1`   `            ``// Else set the value of count` `            ``// for this new digit` `            ``// accordingly from max_digit[]` `            ``ans = (ans + (findCountUtil(` `                  ``N, maxDigit, position + 1, i,` `                  ``(previous == i && position != 0) ? ` `                  ``count - 1 : maxDigit[i] - 1)) % MOD) % MOD;` `        ``}` `    ``}    ` `    ``return` `ans;` `}`   `// Function to count N digit numbers` `// with digit i not appearing more` `// than max_digit[i] consecutive times` `static` `void` `findCount(``int` `N, ``int` `[]maxDigit)` `{` `    ``int` `position = 0; ` `    ``int` `previous = 0; ` `    ``int` `count = 1;` `    `  `    ``// Stores the readonly count` `    ``int` `ans = findCountUtil(N, maxDigit, position,` `                            ``previous, count);`   `    ``// Print the total count` `    ``Console.WriteLine(ans);` `}`   `// Driver Code    ` `public` `static` `void` `Main(String[] args)    ` `{    ` `    ``int` `N = 2;` `    ``int``[] maxDigit = { 1, 1, 1, 1, 1,` `                       ``1, 1, 1, 1, 1 };`   `    ``// Initialize the dp array with -1` `    ``// Fill each row with -1.  ` `    ``for``(``int` `i = 0; i < dp.GetLength(0); i++)` `    ``{` `        ``for` `(``int` `j = 0; j < dp.GetLength(1); j++)` `        ``{` `            ``for` `(``int` `k = 0; k < dp.GetLength(2); k++)` `                ``dp[i, j, k] = -1;` `        ``}` `    ``}` `    `  `    ``// Function Call` `    ``findCount(N, maxDigit);` `}` `}`   `// This code is contributed by 29AjayKumar`

Javascript

 ``

Output:

`90`

Time Complexity: O(N*10*10)
Auxiliary Space: O(N*10*10)

My Personal Notes arrow_drop_up
Recommended Articles
Page :