Given an array arr[] containing N elements, each element is between 0 to 9. The task is to count the number of ways modulo 109 + 7 these operations can be performed so that at the end array with digit K left. Following operations are allowed on the array and any of the operations can be performed more than one time.
- Remove two leftmost elements x and y from the array and insert (x + y) % 10 at the left end of the array.
- Remove two leftmost elements x and y from the array and insert (x * y) % 10 at the left end of the array.
Examples:
Input: arr[] = {2, 7, 6}, K = 4
Output: 2
Explanation: Perform Operation 1 first and then Operation 2: The sequence becomes (2, 7, 6) ? (9, 6)? (4).
Perform Operation 2 first and then Operation 2 again: The sequence becomes (2, 7, 6) ? (4, 6)? (4).Input: arr[] = {0 1 2 3 4}, K = 0
Output: 6
Naive approach: The problem can be solved by using the following idea:
Basic way to solve this problem is to generate all 2N combinations by recursive brute force.
Time Complexity: O(2N)
Auxiliary Space: O(1)
Efficient Approach: The above approach can be optimized based on the following idea:
Dynamic programming can be used to solve this problem. It can be observed that there are N * 10 states but the recursive function is called exponential times. That means that some states are called repeatedly. So the idea is to store the value of states.
Follow the steps below to solve the problem:
- Create a recursive function that takes three parameters i representing i’th index, j representing the leftmost array element after the operation, and K representing the digit whose count at the end has to find out.
- Check the base case if j is equal to K return 1 else return 0.
- Create a 2d array of dp[100001][10] with initially filled with -1.
- If the answer for a particular state is computed then save it in dp[i][j].
- If the answer for a particular state is already computed then just return dp[i][j].
- Initialize a variable and to store the final result.
- Perform operation 1 by making recursive call ans+= call( i+ 1, (j + arr[i + 1])).
- Perform operation 2 by making recursive call ans+= call(i + 1, (j * arr[i + 1])).
- Return the answer.
Below is the implementation of the above approach.
// C++ code to implement the approach #include <bits/stdc++.h> using namespace std;
const int mod = 1e9 + 7;
// dp table initialized with - 1 int dp[100001][10];
// recursive function to count ways of performing // following operations and finally ending up with K int recur( int i, int j, int K, int arr[], int N)
{ // Base case
if (i == N - 1) {
// return 1 if at end K is left
if (j == K)
return 1;
else
return 0;
}
// if answer for current state is already
// calculated then just return dp[i][j]
if (dp[i][j] != -1)
return dp[i][j];
// count of ways for creating K at end
int ans = 0;
// call recursive function for performing operation 1
ans += recur(i + 1, (j + arr[i + 1]) % 10, K, arr, N)
% mod;
// call recursive function for performing operation 2
ans += recur(i + 1, (j * arr[i + 1]) % 10, K, arr, N)
% mod;
// save and return dp value
return dp[i][j] = ans;
} // counting ways of performing following // operations to end with K as last number. void countWaysK( int arr[], int N, int K)
{ // initializing dp with -1
memset (dp, -1, sizeof (dp));
cout << recur(0, arr[0], K, arr, N) << endl;
} // Driver Code int main()
{ // Input 1
int arr[] = { 2, 7, 6 };
int N = sizeof (arr) / sizeof (arr[0]);
int K = 4;
// Function Call
countWaysK(arr, N, K);
// Input 2
int arr1[] = { 0, 1, 2, 3, 4 };
int N1 = sizeof (arr1) / sizeof (arr[0]);
int K1 = 0;
// Function call
countWaysK(arr1, N1, K1);
return 0;
} |
// Java code to implement the approach import java.io.*;
import java.util.*;
class GFG {
static final int mod = ( int )(1e9 + 7 );
static int [][] dp;
// recursive function to count ways of performing
// following operations and finally ending up with K
static int recur( int i, int j, int K, int [] arr, int N)
{
// Base case
if (i == N - 1 ) {
// return 1 if at end K is left
if (j == K)
return 1 ;
else
return 0 ;
}
// if answer for current state is already
// calculated then just return dp[i][j]
if (dp[i][j] != - 1 )
return dp[i][j];
// count of ways for creating K at end
int ans = 0 ;
// call recursive function for performing operation
// 1
ans += recur(i + 1 , (j + arr[i + 1 ]) % 10 , K, arr,
N)
% mod;
// call recursive function for performing operation
// 2
ans += recur(i + 1 , (j * arr[i + 1 ]) % 10 , K, arr,
N)
% mod;
// save and return dp value
return dp[i][j] = ans;
}
// counting ways of performing following
// operations to end with K as last number.
static void countWaysK( int [] arr, int N, int K)
{
// initializing dp with -1
dp = new int [ 100001 ][ 10 ];
for ( int [] row : dp) {
Arrays.fill(row, - 1 );
}
System.out.println(recur( 0 , arr[ 0 ], K, arr, N));
}
// Driver Code
public static void main(String[] args)
{
// Input 1
int [] arr = { 2 , 7 , 6 };
int N = arr.length;
int K = 4 ;
// Function Call
countWaysK(arr, N, K);
// Input 2
int [] arr1 = { 0 , 1 , 2 , 3 , 4 };
int N1 = arr1.length;
int K1 = 0 ;
// Function call
countWaysK(arr1, N1, K1);
}
} // This code is contributed by lokeshmvs21. |
# Python code to implement the approach mod = 1e9 + 7
# dp table initialized with - 1 dp = [[ - 1 for i in range ( 10 )] for j in range ( 100001 )]
# recursive function to count ways of performing # following operations and finally ending up with K def recur(i, j, K, arr, N):
# Base case
if (i = = N - 1 ):
# return 1 if at end K is left
if (j = = K):
return 1
else :
return 0
# if answer for current state is already
# calculated then just return dp[i][j]
if (dp[i][j]! = - 1 ):
return dp[i][j]
# count of ways for creating K at end
ans = 0
# call recursive function for performing operation 1
ans + = recur(i + 1 , (j + arr[i + 1 ]) % 10 , K, arr, N) % mod
# call recursive function for performing operation 2
ans + = recur(i + 1 , (j * arr[i + 1 ]) % 10 , K, arr, N) % mod
# save and return dp value
dp[i][j] = int (ans)
return dp[i][j]
# counting ways of performing following # operations to end with K as last number. def countWaysK(arr, N, K):
# initializing dp with -1
for i in range ( len (dp)):
for j in range ( len (dp[ 0 ])):
dp[i][j] = - 1
print (recur( 0 , arr[ 0 ], K, arr, N))
# Driver Code #Input 1 arr = [ 2 , 7 , 6 ]
N = len (arr)
K = 4
# Function Call countWaysK(arr, N, K) #Input 2 arr1 = [ 0 , 1 , 2 , 3 , 4 ]
N1 = len (arr1)
K1 = 0
# Function Call countWaysK(arr1, N1, K1) # This code is contributed by Pushpesh Raj. |
// C# code implementation for the above approach using System;
using System.Linq;
public class GFG {
static readonly int mod = ( int )(1e9 + 7);
static int [][] dp;
// recursive function to count ways of performing
// following operations and finally ending up with K
static int recur( int i, int j, int K, int [] arr, int N)
{
// Base case
if (i == N - 1)
{
// return 1 if at end K is left
if (j == K)
return 1;
else
return 0;
}
// if answer for current state is already
// calculated then just return dp[i][j]
if (dp[i][j] != -1)
return dp[i][j];
// count of ways for creating K at end
int ans = 0;
// call recursive function for performing operation
// 1
ans += recur(i + 1, (j + arr[i + 1]) % 10, K, arr,
N)
% mod;
// call recursive function for performing operation
// 2
ans += recur(i + 1, (j * arr[i + 1]) % 10, K, arr,
N)
% mod;
// save and return dp value
return dp[i][j] = ans;
}
// counting ways of performing following
// operations to end with K as last number.
static void countWaysK( int [] arr, int N, int K)
{
// initializing dp with -1
dp = Enumerable.Range(0, 100001)
.Select(
x
=> Enumerable.Range(0, 10).ToArray())
.ToArray();
for ( int i = 0; i < dp.Length; i++) {
for ( int j = 0; j < dp[i].Length; j++) {
dp[i][j] = -1;
}
}
Console.WriteLine(recur(0, arr[0], K, arr, N));
}
static public void Main()
{
// Code
// Input 1
int [] arr = { 2, 7, 6 };
int N = arr.Length;
int K = 4;
// Function Call
countWaysK(arr, N, K);
// Input 2
int [] arr1 = { 0, 1, 2, 3, 4 };
int N1 = arr1.Length;
int K1 = 0;
// Function call
countWaysK(arr1, N1, K1);
}
} // This code is contributed by lokesh. |
// JavaScript code to implement the approach let mod = 1e9 + 7; // dp table initialized with - 1 let dp = new Array(100001);
for (let i = 0; i < 100001; i++){
dp[i] = new Array(10).fill(-1);
} // recursive function to count ways of performing // following operations and finally ending up with K function recur(i, j, K, arr, N)
{ // Base case
if (i == N - 1) {
// return 1 if at end K is left
if (j == K)
return 1;
else
return 0;
}
// if answer for current state is already
// calculated then just return dp[i][j]
if (dp[i][j] != -1)
return dp[i][j];
// count of ways for creating K at end
let ans = 0;
// call recursive function for performing operation 1
ans += recur(i + 1, (j + arr[i + 1]) % 10, K, arr, N)
% mod;
// call recursive function for performing operation 2
ans += recur(i + 1, (j * arr[i + 1]) % 10, K, arr, N)
% mod;
// save and return dp value
return dp[i][j] = ans;
} // counting ways of performing following // operations to end with K as last number. function countWaysK(arr, N, K)
{ console.log(recur(0, arr[0], K, arr, N))
} // Driver Code // Input 1
let arr = [2, 7, 6 ];
let N = arr.length;
let K = 4;
// Function Call
countWaysK(arr, N, K);
// Input 2
let arr1 = [0, 1, 2, 3, 4];
let N1 = arr1.length;
let K1 = 0;
// Function call
countWaysK(arr1, N1, K1);
// This code is contributed by poojaagarwal2.
|
2 6
Time Complexity: O(N)
Auxiliary Space: O(N)
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 + memoization(top-down) because memoization method needs extra stack space of recursion calls.
Implementation :
#include <bits/stdc++.h> using namespace std;
const int mod = 1e9 + 7;
// function to count ways of performing // operations and ending up with K void countWaysK( int arr[], int N, int K)
{ // dp table to store the counts
// initialize with all zeros
int dp[N][10];
memset (dp, 0, sizeof (dp));
// initialize the first row of the table
for ( int j = 0; j < 10; j++) {
if (j == arr[0]) {
dp[0][j] = 1;
}
}
// fill the remaining rows of the table
for ( int i = 1; i < N; i++) {
for ( int j = 0; j < 10; j++) {
// for each cell, calculate the counts
// by considering the two operations
dp[i][(j + arr[i]) % 10]
= (dp[i][(j + arr[i]) % 10] + dp[i - 1][j])
% mod;
dp[i][(j * arr[i]) % 10]
= (dp[i][(j * arr[i]) % 10] + dp[i - 1][j])
% mod;
}
}
// the final answer is in dp[N-1][K]
cout << dp[N - 1][K] << endl;
} // Driver Code int main()
{ // Input 1
int arr[] = { 2, 7, 6 };
int N = sizeof (arr) / sizeof (arr[0]);
int K = 4;
// Function Call
countWaysK(arr, N, K);
// Input 2
int arr1[] = { 0, 1, 2, 3, 4 };
int N1 = sizeof (arr1) / sizeof (arr[0]);
int K1 = 0;
// Function call
countWaysK(arr1, N1, K1);
return 0;
} |
import java.util.Arrays;
public class Main {
static final int mod = ( int ) 1e9 + 7 ;
// function to count ways of performing
// operations and ending up with K
public static void countWaysK( int [] arr, int N, int K) {
// dp table to store the counts
// initialize with all zeros
int [][] dp = new int [N][ 10 ];
// initialize the first row of the table
for ( int [] row : dp) {
Arrays.fill(row, 0 );
}
for ( int j = 0 ; j < 10 ; j++) {
if (j == arr[ 0 ]) {
dp[ 0 ][j] = 1 ;
}
}
// fill the remaining rows of the table
for ( int i = 1 ; i < N; i++) {
for ( int j = 0 ; j < 10 ; j++) {
// for each cell, calculate the counts
// by considering the two operations
dp[i][(j + arr[i]) % 10 ] = (dp[i][(j + arr[i]) % 10 ] + dp[i - 1 ][j]) % mod;
dp[i][(j * arr[i]) % 10 ] = (dp[i][(j * arr[i]) % 10 ] + dp[i - 1 ][j]) % mod;
}
}
// the final answer is in dp[N-1][K]
System.out.println(dp[N - 1 ][K]);
}
// Driver Code
public static void main(String[] args) {
int [] arr = { 2 , 7 , 6 };
int N = arr.length;
int K = 4 ;
countWaysK(arr, N, K);
int [] arr1 = { 0 , 1 , 2 , 3 , 4 };
int N1 = arr1.length;
int K1 = 0 ;
countWaysK(arr1, N1, K1);
}
} |
mod = 10 * * 9 + 7
# function to count ways of performing # operations and ending up with K def countWaysK(arr, N, K):
# dp table to store the counts
# initialize with all zeros
dp = [[ 0 ] * 10 for _ in range (N)]
# initialize the first row of the table
for j in range ( 10 ):
if j = = arr[ 0 ]:
dp[ 0 ][j] = 1
# fill the remaining rows of the table
for i in range ( 1 , N):
for j in range ( 10 ):
# for each cell, calculate the counts
# by considering the two operations
dp[i][(j + arr[i]) % 10 ] = (dp[i][(j + arr[i]) % 10 ] + dp[i - 1 ][j]) % mod
dp[i][(j * arr[i]) % 10 ] = (dp[i][(j * arr[i]) % 10 ] + dp[i - 1 ][j]) % mod
# the final answer is in dp[N-1][K]
print (dp[N - 1 ][K])
# Driver code arr = [ 2 , 7 , 6 ]
N = len (arr)
K = 4
countWaysK(arr, N, K) arr1 = [ 0 , 1 , 2 , 3 , 4 ]
N1 = len (arr1)
K1 = 0
countWaysK(arr1, N1, K1) |
using System;
namespace CodeTranslationAssistant
{ class Program
{
const int mod = 1000000007;
// function to count ways of performing
// operations and ending up with K
static void CountWaysK( int [] arr, int N, int K)
{
// dp table to store the counts
// initialize with all zeros
int [,] dp = new int [N, 10];
// initialize the first row of the table
for ( int i = 0; i < N; i++)
{
for ( int j = 0; j < 10; j++)
{
dp[i, j] = 0;
}
}
for ( int j = 0; j < 10; j++)
{
if (j == arr[0])
{
dp[0, j] = 1;
}
}
// fill the remaining rows of the table
for ( int i = 1; i < N; i++)
{
for ( int j = 0; j < 10; j++)
{
// for each cell, calculate the counts
// by considering the two operations
dp[i, (j + arr[i]) % 10] =
(dp[i, (j + arr[i]) % 10] + dp[i - 1, j]) % mod;
dp[i, (j * arr[i]) % 10] =
(dp[i, (j * arr[i]) % 10] + dp[i - 1, j]) % mod;
}
}
// the final answer is in dp[N-1][K]
Console.WriteLine(dp[N - 1, K]);
}
// Driver Code
static void Main( string [] args)
{
int [] arr = { 2, 7, 6 };
int N = arr.Length;
int K = 4;
CountWaysK(arr, N, K);
int [] arr1 = { 0, 1, 2, 3, 4 };
int N1 = arr1.Length;
int K1 = 0;
CountWaysK(arr1, N1, K1);
}
}
} |
const mod = 10**9 + 7; // Function to count ways of performing // operations and ending up with K function countWaysK(arr, N, K) {
// DP table to store the counts
// Initialize with all zeros
const dp = new Array(N);
for (let i = 0; i < N; i++) {
dp[i] = new Array(10).fill(0);
}
// Initialize the first row of the table
for (let j = 0; j < 10; j++) {
if (j === arr[0]) {
dp[0][j] = 1;
}
}
// Fill the remaining rows of the table
for (let i = 1; i < N; i++) {
for (let j = 0; j < 10; j++) {
// For each cell, calculate the counts
// by considering the two operations
dp[i][(j + arr[i]) % 10] = (dp[i][(j + arr[i]) % 10] + dp[i - 1][j]) % mod;
dp[i][(j * arr[i]) % 10] = (dp[i][(j * arr[i]) % 10] + dp[i - 1][j]) % mod;
}
}
// The final answer is in dp[N-1][K]
console.log(dp[N - 1][K]);
} // Driver code const arr = [2, 7, 6]; const N = arr.length; const K = 4; countWaysK(arr, N, K); const arr1 = [0, 1, 2, 3, 4]; const N1 = arr1.length; const K1 = 0; countWaysK(arr1, N1, K1); // This code is contributed by Dwaipayan Bandyopadhyay |
2 6
Time Complexity: O(N*10)
Auxiliary Space: O(N*10)
Related Articles:
- Introduction to Dynamic Programming – Data Structures and Algorithms Tutorials
- Introduction to Arrays – Data Structures and Algorithms Tutorials