Count ways to split an array into subarrays such that sum of the i-th subarray is divisible by i
Last Updated :
31 Aug, 2021
Given an array arr[] consisting of N integers, the task is to find the number of ways to split the array into non-empty subarrays such that the sum of the ith subarray is divisible by i.
Examples:
Input: arr[] = {1, 2, 3, 4}
Output: 3
Explanation:
Following are the number of ways to split the array into non-empty subarray as:
- Split the array into subarray as {1}, {2}, {3}, {4} and the sum of each of the ith subarray is divisible by i.
- Split the array into subarray as {1, 2, 3}, {4} and each of the ith subarray is divisible by i.
- Split the array into subarray as {1, 2, 3, 4} and each of the ith subarray is divisible by i.
As there are only 3 possible ways to split the given array. Therefore, print 3.
Input: arr[ ] = {1, 1, 1, 1, 1}
Output: 3
Approach: The given problem can be solved by using Dynamic Programming because it has overlapping subproblems and optimal substructure. The subproblems can be stored in dp[][] table using memoization where dp[i][j] stores the number of partitions till ith index of arr[] into j non-empty subarray. This idea can be implemented using the Prefix Sum array pre[] that store the sum of all elements till every ith index and dp[i][j] can be calculated as the sum of dp[k][j – 1] for all value of k < i such that (pre[i] – pre[k]) is a multiple of j. Follow the steps below to solve the given problem:
- Initialize a variable, say count that stores the number of possible splitting of the given array into subarray.
- Find the prefix sum of the array and store it in another array, say prefix[].
- Initialize a 2D array, say dp[][] that stores all the overlapping states dp[i][j].
- Iterate over the range [0, N] using the variable i and nested iterate over the range [N, 0] using the variable j and perform the following steps:
- Increment the value of dp[j + 1][pre[i + 1] % (j + 1)] by the value of dp[j][pre[i + 1] % j] as this denotes the count of partitions till index i into j continuous subsequence divisible by (j + 1).
- If the value of i is (N – 1), then update the value of count by dp[j][pre[i + 1] % j].
- After completing the above steps, print the value of count as the result.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int countOfWays( int arr[], int N)
{
int pre[N + 1] = { 0 };
for ( int i = 0; i < N; i++) {
pre[i + 1] = pre[i] + arr[i];
}
int dp[N + 1][N + 1];
memset (dp, 0, sizeof (dp));
dp[1][0]++;
int ans = 0;
for ( int i = 0; i < N; i++) {
for ( int j = N; j >= 1; j--) {
dp[j + 1][pre[i + 1] % (j + 1)]
+= dp[j][pre[i + 1] % j];
if (i == N - 1) {
ans += dp[j][pre[i + 1] % j];
}
}
}
return ans;
}
int main()
{
int arr[] = { 1, 2, 3, 4 };
int N = sizeof (arr) / sizeof (arr[0]);
cout << countOfWays(arr, N);
return 0;
}
|
Java
public class GFG {
static int countOfWays( int arr[], int N)
{
int pre[] = new int [N + 1 ];
for ( int i = 0 ; i < N; i++) {
pre[i + 1 ] = pre[i] + arr[i];
}
int dp[][] = new int [N + 2 ][N + 2 ];
dp[ 1 ][ 0 ]++;
int ans = 0 ;
for ( int i = 0 ; i < N; i++) {
for ( int j = N; j >= 1 ; j--) {
dp[j + 1 ][pre[i + 1 ] % (j + 1 )]
+= dp[j][pre[i + 1 ] % j];
if (i == N - 1 ) {
ans += dp[j][pre[i + 1 ] % j];
}
}
}
return ans;
}
public static void main (String[] args) {
int arr[] = { 1 , 2 , 3 , 4 };
int N = arr.length;
System.out.println(countOfWays(arr, N));
}
}
|
Python3
import numpy as np
def countOfWays(arr, N) :
pre = [ 0 ] * (N + 1 );
for i in range (N) :
pre[i + 1 ] = pre[i] + arr[i];
dp = np.zeros((N + 2 ,N + 2 ));
dp[ 1 ][ 0 ] + = 1 ;
ans = 0 ;
for i in range (N) :
for j in range (N, 0 , - 1 ) :
dp[j + 1 ][pre[i + 1 ] % (j + 1 )] + = dp[j][pre[i + 1 ] % j];
if (i = = N - 1 ) :
ans + = dp[j][pre[i + 1 ] % j];
return ans;
if __name__ = = "__main__" :
arr = [ 1 , 2 , 3 , 4 ];
N = len (arr);
print (countOfWays(arr, N));
|
C#
using System;
public class GFG
{
static int countOfWays( int [] arr, int N)
{
int [] pre = new int [N + 1];
for ( int i = 0; i < N; i++) {
pre[i + 1] = pre[i] + arr[i];
}
int [,] dp = new int [N + 2, N + 2];
dp[1, 0]++;
int ans = 0;
for ( int i = 0; i < N; i++) {
for ( int j = N; j >= 1; j--) {
dp[j + 1, pre[i + 1] % (j + 1)]
+= dp[j, pre[i + 1] % j];
if (i == N - 1) {
ans += dp[j, pre[i + 1] % j];
}
}
}
return ans;
}
public static void Main(String []args) {
int [] arr = { 1, 2, 3, 4 };
int N = arr.Length;
Console.WriteLine(countOfWays(arr, N));
}
}
|
Javascript
<script>
function countOfWays(arr, N)
{
let pre = new Array(N + 1).fill(0);
for (let i = 0; i < N; i++)
{
pre[i + 1] = pre[i] + arr[i];
}
let dp = new Array(N + 2).fill(0).map(() => new Array(N + 2).fill(0));
dp[1][0]++;
let ans = 0;
for (let i = 0; i < N; i++) {
for (let j = N; j >= 1; j--) {
dp[j + 1][pre[i + 1] % (j + 1)] += dp[j][pre[i + 1] % j];
if (i == N - 1) {
ans += dp[j][pre[i + 1] % j];
}
}
}
return ans;
}
let arr = [1, 2, 3, 4];
let N = arr.length;
document.write(countOfWays(arr, N));
</script>
|
Time Complexity: O(N2)
Auxiliary Space: O(N2)
Like Article
Suggest improvement
Share your thoughts in the comments
Please Login to comment...