Count N-digit numbers made up of X or Y whose sum of digits is also made up of X or Y
Given three positive integers N, X, and Y, the task is to count N-digit numbers containing of X or Y only as digits and the sum of digits also contains X or Y. Since the count can be very large, print the count modulo 109 + 7.
Examples:
Input: N = 2, X = 1, Y = 2
Output: 1
Explanation: All possible 2-digit numbers that can be formed using X and Y are 11, 12, 21, 22. Among them, only 11 is a valid number since its sum of digits is 2 (= Y).
Input: N = 3, X = 1, Y = 5
Output: 4
Explanation: All possible 3-digit numbers that can be formed using X and Y are 111, 115, 151, 155. But only 155, 515, 551 and 555 satisfies the given condition. Therefore, the count is 4.
Naive Approach: The simplest approach to solve this problem by using recursion. At each step, there are 2 choices, to place digit X or Y at the current position and calculate the sum of digits when the length of the formed number becomes equal to N. If the sum is also formed of only X or Y the count this number. After checking all the numbers print the count modulo 109 + 7.
Time Complexity: O(2N)
Auxiliary Space: O(1)
Efficient Approach: The above approach can be optimized by using Dynamic Programming since this problem has both properties of Optimal Substructure and Overlapping Subproblems. The computations of the same subproblems can be avoided by using an auxiliary array dp[N][sum] to store the value when the number of digits left is N and the sum of filled digits is the sum. Below are the steps:
- Initialize an auxiliary array dp[][] to store intermediate computations.
- At each step, there are 2 choices to place digit X or Y at the current position.
- When the number of digits left is 0, check if the sum of digits can be made using X or Y. If yes then increment the current state value by 1.
- Else Update the current state as 0.
- If the same subproblem is encountered, return the already computed value modulo 109 + 7.
- Place digit X and digit Y at the current position and recur for the remaining positions, and pass the sum of digits at each step.
- For each recursive call for value x and y, update the current state as the sum of values returned by these states.
- After the above steps, print the value of dp[N][0] as the resultant count.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int dp[1000 + 5][9000 + 5];
int mod = 1000000007;
int check( int sum, int x, int y)
{
while (sum > 0) {
int ln = sum % 10;
if (ln != x && ln != y) {
return 0;
}
sum /= 10;
}
return 1;
}
int countNumbers( int n, int x, int y, int sum)
{
memset (dp, -1, sizeof (dp));
if (n == 0) {
return check(sum, x, y);
}
if (dp[n][sum] != -1) {
return dp[n][sum] % mod;
}
int option1 = countNumbers(n - 1, x,
y, sum + x) % mod;
int option2 = countNumbers(n - 1, x,
y, sum + y) % mod;
return dp[n][sum] = (option1 + option2) % mod;
}
int main()
{
int N = 3, X = 1, Y = 5;
cout << countNumbers(N, X, Y, 0) % mod;
}
|
Java
import java.util.*;
public class Main {
static int dp[][] = new int [ 1000 + 5 ][ 9000 + 5 ];
static int mod = 1000000007 ;
public static int countNumbers( int n, int x, int y,
int sum)
{
for ( int i[] : dp)
Arrays.fill(i, - 1 );
if (n == 0 ) {
return check(sum, x, y);
}
if (dp[n][sum] != - 1 ) {
return dp[n][sum] % mod;
}
int option1
= countNumbers(n - 1 , x, y, sum + x) % mod;
int option2
= countNumbers(n - 1 , x, y, sum + y) % mod;
return dp[n][sum] = (option1 + option2) % mod;
}
public static int check( int sum, int x, int y)
{
while (sum > 0 ) {
int ln = sum % 10 ;
if (ln != x && ln != y) {
return 0 ;
}
sum /= 10 ;
}
return 1 ;
}
public static void main(String args[])
{
int N = 3 , X = 1 , Y = 5 ;
System.out.println(countNumbers(N, X, Y, 0 ) % mod);
}
}
|
Python3
dp = [[ - 1 for x in range ( 9000 + 5 )]
for y in range ( 1000 + 5 )]
mod = 1000000007
def check( sum , x, y):
while ( sum > 0 ):
ln = sum % 10
if (ln ! = x and ln ! = y):
return 0
sum / / = 10
return 1
def countNumbers(n, x, y, sum ):
global dp
if (n = = 0 ):
return check( sum , x, y)
if (dp[n][ sum ] ! = - 1 ):
return dp[n][ sum ] % mod
option1 = countNumbers(n - 1 , x,
y, sum + x) % mod
option2 = countNumbers(n - 1 , x,
y, sum + y) % mod
dp[n][ sum ] = (option1 + option2) % mod
return dp[n][ sum ]
if __name__ = = "__main__" :
N = 3
X = 1
Y = 5
print (countNumbers(N, X, Y, 0 ) % mod)
|
C#
using System;
class GFG{
static int [,]dp = new int [100 + 5, 900 + 5];
static int mod = 10000007;
public static int countNumbers( int n, int x,
int y, int sum)
{
for ( int i = 0; i < dp.GetLength(0); i++)
{
for ( int j = 0; j < dp.GetLength(1); j++)
{
dp[i, j] = -1;
}
}
if (n == 0)
{
return check(sum, x, y);
}
if (dp[n, sum] != -1)
{
return dp[n, sum] % mod;
}
int option1 = countNumbers(n - 1, x, y,
sum + x) % mod;
int option2 = countNumbers(n - 1, x, y,
sum + y) % mod;
return dp[n,sum] = (option1 + option2) % mod;
}
public static int check( int sum, int x, int y)
{
while (sum > 0)
{
int ln = sum % 10;
if (ln != x && ln != y)
{
return 0;
}
sum /= 10;
}
return 1;
}
public static void Main(String []args)
{
int N = 3, X = 1, Y = 5;
Console.WriteLine(countNumbers(
N, X, Y, 0) % mod);
}
}
|
Javascript
<script>
let dp = [];
for (let i = 0;i<1005;i++){
dp[i] = [];
for (let j = 0;j<9005;j++){
dp[i][j] = 0;
}
}
let mod = 1000000007;
function check( sum, x, y)
{
while (sum > 0) {
let ln = sum % 10;
if (ln != x && ln != y) {
return 0;
}
sum = Math.floor(sum/10);
}
return 1;
}
function countNumbers(n, x, y, sum)
{
for (let i = 0;i<1005;i++){
for (let j = 0;j<9005;j++){
dp[i][j] = -1;
}
}
if (n == 0) {
return check(sum, x, y);
}
if (dp[n][sum] != -1) {
return dp[n][sum] % mod;
}
let option1 = countNumbers(n - 1, x,
y, sum + x) % mod;
let option2 = countNumbers(n - 1, x,
y, sum + y) % mod;
return dp[n][sum] = (option1 + option2) % mod;
}
let N = 3, X = 1, Y = 5;
document.write(countNumbers(N, X, Y, 0) % mod);
</script>
|
Time Complexity:(N*sum)
Auxiliary Space: O(N*sum)
Efficient approach : Using DP Tabulation method ( Iterative approach )
The approach to solve this problem is same but DP tabulation(bottom-up) method is better then Dp + memorization(top-down) because memorization method needs extra stack space of recursion calls.
Steps to solve this problem :
- Create a vector to store the solution of the subproblems.
- Initialize the table with base cases
- Fill up the table iteratively
- Return the final solution
Implementation :
C++
#include <bits/stdc++.h>
using namespace std;
const int N = 1000 + 5, M = 9000 + 5, MOD = 1000000007;
int dp[N][M];
int check( int sum, int x, int y) {
while (sum > 0) {
int ln = sum % 10;
if (ln != x && ln != y) {
return 0;
}
sum /= 10;
}
return 1;
}
int countNumbers( int n, int x, int y, int sum) {
memset (dp, 0, sizeof (dp));
dp[0][0] = 1;
for ( int i = 1; i <= n; i++) {
for ( int j = 0; j <= sum; j++) {
int option1 = (j >= x ? dp[i-1][j-x] : 0);
int option2 = (j >= y ? dp[i-1][j-y] : 0);
dp[i][j] = (option1 + option2) % MOD;
}
}
int ans = 0;
for ( int i = 0; i <= sum; i++) {
ans = (ans + check(i, x, y) * dp[n][i]) % MOD;
}
return ans;
}
int main() {
int n = 3, x = 1, y = 5;
cout << countNumbers(n, x, y, 9000) << endl;
return 0;
}
|
Java
import java.io.*;
import java.util.Arrays;
class GFG{
static final int N = 1000 + 5 , M = 9000 + 5 , MOD = 1000000007 ;
static int [][] dp = new int [N][M];
static int check( int sum, int x, int y) {
while (sum > 0 ) {
int ln = sum % 10 ;
if (ln != x && ln != y) {
return 0 ;
}
sum /= 10 ;
}
return 1 ;
}
static int countNumbers( int n, int x, int y, int sum)
{
for ( int [] row : dp)
Arrays.fill(row, 0 );
dp[ 0 ][ 0 ] = 1 ;
for ( int i = 1 ; i <= n; i++) {
for ( int j = 0 ; j <= sum; j++) {
int option1 = (j >= x ? dp[i - 1 ][j - x] : 0 );
int option2 = (j >= y ? dp[i - 1 ][j - y] : 0 );
dp[i][j] = (option1 + option2) % MOD;
}
}
int ans = 0 ;
for ( int i = 0 ; i <= sum; i++)
{
ans = (ans + check(i, x, y) * dp[n][i]) % MOD;
}
return ans;
}
public static void main(String[] args) {
int n = 3 , x = 1 , y = 5 ;
System.out.println(countNumbers(n, x, y, 9000 ));
}
}
|
Python
MOD = 1000000007
N = 1000 + 5
M = 9000 + 5
dp = [[ 0 for j in range (M)] for i in range (N)]
def check( sum , x, y):
while sum > 0 :
ln = sum % 10
if ln ! = x and ln ! = y:
return 0
sum / / = 10
return 1
def countNumbers(n, x, y, sum ):
for i in range (N):
for j in range (M):
dp[i][j] = 0
dp[ 0 ][ 0 ] = 1
for i in range ( 1 , n + 1 ):
for j in range ( sum + 1 ):
option1 = dp[i - 1 ][j - x] if j > = x else 0
option2 = dp[i - 1 ][j - y] if j > = y else 0
dp[i][j] = (option1 + option2) % MOD
ans = 0
for i in range ( sum + 1 ):
ans = (ans + check(i, x, y) * dp[n][i]) % MOD
return ans
if __name__ = = "__main__" :
n = 3
x = 1
y = 5
print (countNumbers(n, x, y, 9000 ))
|
C#
using System;
class GFG
{
const int N = 1000 + 5;
const int M = 9000 + 5;
const int MOD = 1000000007;
static int [,] dp = new int [N, M];
static int Check( int sum, int x, int y)
{
while (sum > 0)
{
int ln = sum % 10;
if (ln != x && ln != y)
{
return 0;
}
sum /= 10;
}
return 1;
}
static int CountNumbers( int n, int x, int y, int sum)
{
for ( int i = 0; i < N; i++)
{
for ( int j = 0; j < M; j++)
{
dp[i, j] = 0;
}
}
dp[0, 0] = 1;
for ( int i = 1; i <= n; i++)
{
for ( int j = 0; j <= sum; j++)
{
int option1 = (j >= x) ? dp[i - 1, j - x] : 0;
int option2 = (j >= y) ? dp[i - 1, j - y] : 0;
dp[i, j] = (option1 + option2) % MOD;
}
}
int ans = 0;
for ( int i = 0; i <= sum; i++)
{
ans = (ans + Check(i, x, y) * dp[n, i]) % MOD;
}
return ans;
}
static void Main()
{
int n = 3, x = 1, y = 5;
Console.WriteLine(CountNumbers(n, x, y, 9000));
}
}
|
Javascript
const N = 1000 + 5;
const M = 9000 + 5;
const MOD = 1000000007;
let dp = new Array(N);
for (let i = 0; i < N; i++) {
dp[i] = new Array(M).fill(0);
}
function check(sum, x, y) {
while (sum > 0) {
let ln = sum % 10;
if (ln !== x && ln !== y) {
return 0;
}
sum = Math.floor(sum / 10);
}
return 1;
}
function countNumbers(n, x, y, sum) {
for (let i = 0; i <= n; i++) {
for (let j = 0; j <= sum; j++) {
dp[i][j] = 0;
}
}
dp[0][0] = 1;
for (let i = 1; i <= n; i++) {
for (let j = 0; j <= sum; j++) {
let option1 = (j >= x ? dp[i - 1][j - x] : 0);
let option2 = (j >= y ? dp[i - 1][j - y] : 0);
dp[i][j] = (option1 + option2) % MOD;
}
}
let ans = 0;
for (let i = 0; i <= sum; i++) {
ans = (ans + check(i, x, y) * dp[n][i]) % MOD;
}
return ans;
}
const n = 3;
const x = 1;
const y = 5;
console.log(countNumbers(n, x, y, 9000));
|
Output
4
Time Complexity: (N*sum)
Auxiliary Space: O(N*sum)
Last Updated :
04 Nov, 2023
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...