Open In App

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
Comments
Improve
Suggest changes
Like Article
Like
Report

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:

  1. Split the array into subarray as {1}, {2}, {3}, {4} and the sum of each of the ith subarray is divisible by i.
  2. Split the array into subarray as {1, 2, 3}, {4} and each of the ith subarray is divisible by i.
  3. 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:
    1. 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).
    2. 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++
// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;

// Function to count ways to split
// an array into subarrays such that
// sum of the i-th subarray is
// divisible by i
int countOfWays(int arr[], int N)
{

    // Stores the prefix sum of array
    int pre[N + 1] = { 0 };
    for (int i = 0; i < N; i++) {

        // Find the prefix sum
        pre[i + 1] = pre[i] + arr[i];
    }

    // Initialize dp[][] array
    int dp[N + 1][N + 1];
    memset(dp, 0, sizeof(dp));
    dp[1][0]++;

    // Stores the count of splitting
    int ans = 0;

    // Iterate over the range [0, N]
    for (int i = 0; i < N; i++) {
        for (int j = N; j >= 1; j--) {

            // Update the dp table
            dp[j + 1][pre[i + 1] % (j + 1)]
                += dp[j][pre[i + 1] % j];

            // If the last index is
            // reached, then add it
            // to the variable ans
            if (i == N - 1) {
                ans += dp[j][pre[i + 1] % j];
            }
        }
    }

    // Return the possible count of
    // splitting of array into subarrays
    return ans;
}

// Driver Code
int main()
{
    int arr[] = { 1, 2, 3, 4 };
    int N = sizeof(arr) / sizeof(arr[0]);

    cout << countOfWays(arr, N);

    return 0;
}
Java
// Java program for the above approach

public class GFG {
    

// Function to count ways to split
// an array into subarrays such that
// sum of the i-th subarray is
// divisible by i
static int countOfWays(int arr[], int N)
{

    // Stores the prefix sum of array
    int pre[] = new int[N + 1];
    
    for (int i = 0; i < N; i++) {

        // Find the prefix sum
        pre[i + 1] = pre[i] + arr[i];
    }

    // Initialize dp[][] array
    int dp[][] = new int [N + 2][N + 2];

    dp[1][0]++;

    // Stores the count of splitting
    int ans = 0;

    // Iterate over the range [0, N]
    for (int i = 0; i < N; i++) {
        for (int j = N; j >= 1; j--) {

            // Update the dp table
            dp[j + 1][pre[i + 1] % (j + 1)]
                += dp[j][pre[i + 1] % j];

            // If the last index is
            // reached, then add it
            // to the variable ans
            if (i == N - 1) {
                ans += dp[j][pre[i + 1] % j];
            }
        }
    }

    // Return the possible count of
    // splitting of array into subarrays
    return ans;
}

    // Driver Code
    public static void main (String[] args) {
        
            int arr[] = { 1, 2, 3, 4 };
            int N = arr.length;
        
            System.out.println(countOfWays(arr, N));
    }
}

// This code is contributed by AnkThon
Python3
# Python3 program for the above approach

import numpy as np

# Function to count ways to split
# an array into subarrays such that
# sum of the i-th subarray is
# divisible by i
def countOfWays(arr, N) :

    # Stores the prefix sum of array
    pre = [ 0 ] * (N + 1);
    
    for i in range(N) :

        # Find the prefix sum
        pre[i + 1] = pre[i] + arr[i];

    # Initialize dp[][] array
    dp = np.zeros((N + 2,N + 2));
    dp[1][0] += 1;

    # Stores the count of splitting
    ans = 0;

    # Iterate over the range [0, N]
    for i in range(N) :
        for j in range(N, 0, -1) :

            # Update the dp table
            dp[j + 1][pre[i + 1] % (j + 1)] += dp[j][pre[i + 1] % j];

            # If the last index is
            # reached, then add it
            # to the variable ans
            if (i == N - 1) :
                ans += dp[j][pre[i + 1] % j];
           
    # Return the possible count of
    # splitting of array into subarrays
    return ans;


# Driver Code
if __name__ ==  "__main__" :

    arr = [ 1, 2, 3, 4 ];
    N = len(arr);

    print(countOfWays(arr, N));
    
    # This code is contributed by AnkThon
C#
// C# program for the above approach
using System;

public class GFG
{
  
// Function to count ways to split
// an array into subarrays such that
// sum of the i-th subarray is
// divisible by i
static int countOfWays(int[] arr, int N)
{

    // Stores the prefix sum of array
    int[] pre = new int[N + 1];
    
    for (int i = 0; i < N; i++) {

        // Find the prefix sum
        pre[i + 1] = pre[i] + arr[i];
    }

    // Initialize dp[][] array
    int[,] dp = new int [N + 2, N + 2];

    dp[1, 0]++;

    // Stores the count of splitting
    int ans = 0;

    // Iterate over the range [0, N]
    for (int i = 0; i < N; i++) {
        for (int j = N; j >= 1; j--) {

            // Update the dp table
            dp[j + 1, pre[i + 1] % (j + 1)]
                += dp[j, pre[i + 1] % j];

            // If the last index is
            // reached, then add it
            // to the variable ans
            if (i == N - 1) {
                ans += dp[j, pre[i + 1] % j];
            }
        }
    }

    // Return the possible count of
    // splitting of array into subarrays
    return ans;
}

  // Driver Code
  public static void Main(String []args) {
    
    int[] arr = { 1, 2, 3, 4 };
    int N = arr.Length;
        
    Console.WriteLine(countOfWays(arr, N));
  }

}

// This code is contributed by sanjoy_62.
JavaScript
<script>
// Javascript program for the above approach

// Function to count ways to split
// an array into subarrays such that
// sum of the i-th subarray is
// divisible by i
function countOfWays(arr, N)
{

  // Stores the prefix sum of array
  let pre = new Array(N + 1).fill(0);

  for (let i = 0; i < N; i++) 
  {
  
    // Find the prefix sum
    pre[i + 1] = pre[i] + arr[i];
  }

  // Initialize dp[][] array
  let dp = new Array(N + 2).fill(0).map(() => new Array(N + 2).fill(0));

  dp[1][0]++;

  // Stores the count of splitting
  let ans = 0;

  // Iterate over the range [0, N]
  for (let i = 0; i < N; i++) {
    for (let j = N; j >= 1; j--) {
      // Update the dp table
      dp[j + 1][pre[i + 1] % (j + 1)] += dp[j][pre[i + 1] % j];

      // If the last index is
      // reached, then add it
      // to the variable ans
      if (i == N - 1) {
        ans += dp[j][pre[i + 1] % j];
      }
    }
  }

  // Return the possible count of
  // splitting of array into subarrays
  return ans;
}

// Driver Code

let arr = [1, 2, 3, 4];
let N = arr.length;

document.write(countOfWays(arr, N));

// This code is contributed by _Saurabh_Jaiswal

</script>

Output
3

Time Complexity: O(N2)
Auxiliary Space: O(N2)


Next Article

Similar Reads