给定一个整数N和一个数组maxDigit [] ,任务是对所有不同的N位数字进行计数,以使数字i出现的次数不超过maxDigit [i]次。由于计数可能非常大,请以10 9 + 7为模数打印。
例子:
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
天真的方法:最简单的方法是遍历所有N位数字,并对满足给定条件的那些数字进行计数。检查所有数字后,以10 9 + 7为模打印总计数。
时间复杂度: O(N * 10 N )
辅助空间: O(1)
高效方法:为了优化上述方法,其思想是使用数字动态编程的概念。此问题的DP状态解释如下:
- 在Digit-DP中,其想法是通过在每个位置放置一个数字[0,9]来从左到右构建一个数字。因此,要跟踪当前位置,需要具有位置状态。此状态可能具有从0到(N – 1)的值。
- 根据问题,数字i连续出现的次数不能超过maxDigit [i] ,因此请跟踪先前填充的数字。因此,需要一个先前的状态。此状态的可能值从0到9 。
- 需要一个状态计数,该计数将提供一个数字可以连续出现的次数。此状态可能具有从1到maxDigit [i]的值。
请按照以下步骤解决此问题:
- 第一位置可以没有任何限制的任何数字。
- 从第二个位置开始,一直跟踪先前填充的数字及其给定的计数,直到该数字可以连续出现。
- 如果下一个位置出现相同的数字,则减少其计数,如果该计数变为零,则在下一个递归调用中只需忽略该数字即可。
- 如果下一个位置出现另一个数字,则根据maxDigit []中的给定值更新其计数。
- 在上述每个递归调用中,当生成结果编号时,然后递增该编号的计数。
- 完成上述步骤后,打印总计数值作为结果。
下面是上述方法的实现:
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)
# Prthe 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
90
时间复杂度: O(N * 10 * 10)
辅助空间: O(N * 10 * 10)