Open In App

Minimum sum of multiplications of n numbers

Last Updated : 04 May, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Given an integer array arr[] of length n. Your goal is to reduce the array to a single element by repeatedly applying the following operation

  • Select any two adjacent elements, call them x and y.
  • Remove x and y from the array.
  • Insert a new element equal to (x + y) mod 100 at their position.
  • The cost of this operation is x * y.

You must perform exactly n‑1 operations (so that one element remains), and your task is to minimize the total cost, i.e., the sum of all individual x * y costs.

Examples:

Input: arr[] = [40, 60, 20]
Output: 2400
Explanation: There are two possible cases:
Sequence 1:
1. Combine 40 & 60 → cost 2400, new element 0 → [0, 20]
2. Combine 0 & 20 → cost 0, new element 20 → [20], and total becomes 2400.
Sequence 2:
1. Combine 60 & 20 → cost 1200, new element 80 → [40, 80]
2. Combine 40 & 80 → cost 3200, new element 20 → [20], and total becomes 4400.

Input: arr[] = [5, 6]
Output: 30
Explanation: There is only one possible operation, 5 * 6 = 30.

[Expected Approach - 1] - Using Memoization and Prefix Sum - O(n ^ 3) Time and O(n ^ 2) Space

The idea is to partition the array in every possible way, similar to Matrix chain Multiplication Dynamic Programming, and find the minimum possible cost. To do so, firstly create the 2d array memo[][] where each element memo[i][j], stores the minimum cost required to perform the given operation for the subarray arr[i..j]. Now start for the whole array, and recursively calculate the cost of smaller subparts, and add the multiplication and store the minimum of them. For the subarray arr[i...j], the value memo[i][j] will be calculated as:
memo[i][j] = min(memo[i][k] + memo[k + 1][j] + modSum(i, k) * modSum(k + 1, j)), for i <= k < j.

Follow the below given steps:

  • Build a prefix‑sum array (prefix) so that you can get the sum of any subarray in O(1) time via a simple subtraction and modulo operation.
  • Create an n×n table (memo) initialized to –1 to indicate “not yet computed.”
  • Call findMinCost(arr, 0, n‑1, prefix, memo) and return its value.
  • In findMinCost(arr, i, j, prefix, memo):
    • If i == j, return 0.
    • If memo[i][j] != -1, return the stored value.
    • Set memo[i][j] = INT_MAX.
    • For k from i to j‑1:
      • Compute a = findMinCost(arr, i, k, prefix, memo).
      • Compute b = findMinCost(arr, k+1, j, prefix, memo).
      • Compute c = sum(i, k, prefix) * sum(k+1, j, prefix).
      • Update memo[i][j] = min(memo[i][j], a + b + c).
    • Return memo[i][j].

Below is given the implementation:

C++
#include <bits/stdc++.h>
using namespace std;

// function to calculate the 
// sum from a[i] to a[j]
int sum(int i, int j, vector<int> &prefix) {     
    if (i == 0)
        return prefix[j] % 100;
    return (prefix[j] - prefix[i - 1]) % 100;
}

int findMinCost(vector<int> &arr, int i, int j, 
    vector<int> &prefix, vector<vector<int>> &memo) {

    // base case 
    if (i == j)
        return 0; 
    
    // if already computed
    if (memo[i][j] != -1)
        return memo[i][j];
    
    // store a max value 
    memo[i][j] = INT_MAX;
    
    // partition the array at every index
    for (int k = i; k < j; k++) {

        // calculate the cost of the partition
        int a = findMinCost(arr, i, k, prefix, memo);
        int b = findMinCost(arr, k + 1, j, prefix, memo);
        int c = sum(i, k, prefix) * sum(k + 1, j, prefix);
        int cost = a + b + c;

        // store the minimum cost
        memo[i][j] = min(memo[i][j], cost);
    }
    
    // return the minimum 
    return memo[i][j];
}

int minCost(vector<int> &arr) {
    int n = arr.size();

    // initialize the memo
    vector<vector<int>> memo(n, vector<int>(n, -1));

    // to store prefix sum
    vector<int> prefix(n);
    prefix[0] = arr[0];
    for(int i = 1; i < n; i++) {
        prefix[i] = arr[i] + prefix[i - 1];
    }

    return findMinCost(arr, 0, n - 1, prefix, memo);
}

int main() {
    vector<int> arr = {40, 60, 20};
    cout << minCost(arr);
    return 0;
}
Java
import java.util.*;

public class GfG {

    public static int sum(int i, int j, List<Integer> prefix) {     

        // function to calculate the 
        // sum from a[i] to a[j]
        if (i == 0)
            return prefix.get(j) % 100;
        return (prefix.get(j) - prefix.get(i - 1)) % 100;
    }

    public static int findMinCost(List<Integer> arr, int i, int j, 
        List<Integer> prefix, int[][] memo) {

        // base case 
        if (i == j)
            return 0; 
    
        // if already computed
        if (memo[i][j] != -1)
            return memo[i][j];
    
        // store a max value 
        memo[i][j] = Integer.MAX_VALUE;
    
        // partition the array at every index
        for (int k = i; k < j; k++) {

            // calculate the cost of the partition
            int a = findMinCost(arr, i, k, prefix, memo);
            int b = findMinCost(arr, k + 1, j, prefix, memo);
            int c = sum(i, k, prefix) * sum(k + 1, j, prefix);
            int cost = a + b + c;

            // store the minimum cost
            memo[i][j] = Math.min(memo[i][j], cost);
        }
    
        // return the minimum 
        return memo[i][j];
    }

    public static int minCost(List<Integer> arr) {
        int n = arr.size();

        // initialize the memo
        int[][] memo = new int[n][n];
        for (int[] row : memo) Arrays.fill(row, -1);

        // to store prefix sum
        List<Integer> prefix = new ArrayList<>();
        prefix.add(arr.get(0));
        for (int i = 1; i < n; i++) {
            prefix.add(arr.get(i) + prefix.get(i - 1));
        }

        return findMinCost(arr, 0, n - 1, prefix, memo);
    }

    public static void main(String[] args) {
        List<Integer> arr = Arrays.asList(40, 60, 20);
        System.out.print(minCost(arr));
    }
}
Python
# function to calculate the 
# sum from a[i] to a[j]
def sum(i, j, prefix):
    if i == 0:
        return prefix[j] % 100
    return (prefix[j] - prefix[i - 1]) % 100

def findMinCost(arr, i, j,
    prefix, memo):

    # base case 
    if i == j:
        return 0

    # if already computed
    if memo[i][j] != -1:
        return memo[i][j]

    # store a max value 
    memo[i][j] = float('inf')

    # partition the array at every index
    for k in range(i, j):
        # calculate the cost of the partition
        a = findMinCost(arr, i, k, prefix, memo)
        b = findMinCost(arr, k + 1, j, prefix, memo)
        c = sum(i, k, prefix) * sum(k + 1, j, prefix)
        cost = a + b + c

        # store the minimum cost
        memo[i][j] = min(memo[i][j], cost)

    # return the minimum 
    return memo[i][j]

def minCost(arr):
    n = len(arr)

    # initialize the memo
    memo = [[-1] * n for _ in range(n)]

    # to store prefix sum
    prefix = [0] * n
    prefix[0] = arr[0]
    for i in range(1, n):
        prefix[i] = arr[i] + prefix[i - 1]

    return findMinCost(arr, 0, n - 1, prefix, memo)

if __name__ == "__main__":
    arr = [40, 60, 20]
    print(minCost(arr))
C#
using System;
using System.Collections.Generic;

public class GfG {

    public static int sum(int i, int j, List<int> prefix) {     

        // function to calculate the 
        // sum from a[i] to a[j]
        if (i == 0)
            return prefix[j] % 100;
        return (prefix[j] - prefix[i - 1]) % 100;
    }

    public static int findMinCost(List<int> arr, int i, int j, 
        List<int> prefix, int[,] memo) {

        // base case 
        if (i == j)
            return 0; 
    
        // if already computed
        if (memo[i, j] != -1)
            return memo[i, j];
    
        // store a max value 
        memo[i, j] = int.MaxValue;
    
        // partition the array at every index
        for (int k = i; k < j; k++) {

            // calculate the cost of the partition
            int a = findMinCost(arr, i, k, prefix, memo);
            int b = findMinCost(arr, k + 1, j, prefix, memo);
            int c = sum(i, k, prefix) * sum(k + 1, j, prefix);
            int cost = a + b + c;

            // store the minimum cost
            memo[i, j] = Math.Min(memo[i, j], cost);
        }
    
        // return the minimum 
        return memo[i, j];
    }

    public static int minCost(List<int> arr) {
        int n = arr.Count;

        // initialize the memo
        int[,] memo = new int[n, n];
        for (int x = 0; x < n; x++)
            for (int y = 0; y < n; y++)
                memo[x, y] = -1;

        // to store prefix sum
        List<int> prefix = new List<int>();
        prefix.Add(arr[0]);
        for (int i = 1; i < n; i++) {
            prefix.Add(arr[i] + prefix[i - 1]);
        }

        return findMinCost(arr, 0, n - 1, prefix, memo);
    }

    public static void Main() {
        List<int> arr = new List<int> {40, 60, 20};
        Console.Write(minCost(arr));
    }
}
JavaScript
// function to calculate the 
// sum from a[i] to a[j]
function sum(i, j, prefix) {
    if (i === 0)
        return prefix[j] % 100;
    return (prefix[j] - prefix[i - 1]) % 100;
}

function findMinCost(arr, i, j,
    prefix, memo) {

    // base case 
    if (i === j)
        return 0;

    // if already computed
    if (memo[i][j] !== -1)
        return memo[i][j];

    // store a max value 
    memo[i][j] = Number.MAX_SAFE_INTEGER;

    // partition the array at every index
    for (let k = i; k < j; k++) {

        // calculate the cost of the partition
        let a = findMinCost(arr, i, k, prefix, memo);
        let b = findMinCost(arr, k + 1, j, prefix, memo);
        let c = sum(i, k, prefix) * sum(k + 1, j, prefix);
        let cost = a + b + c;

        // store the minimum cost
        memo[i][j] = Math.min(memo[i][j], cost);
    }

    // return the minimum 
    return memo[i][j];
}

function minCost(arr) {
    const n = arr.length;

    // initialize the memo
    const memo = Array.from({ length: n }, () => Array(n).fill(-1));

    // to store prefix sum
    const prefix = [];
    prefix[0] = arr[0];
    for (let i = 1; i < n; i++) {
        prefix[i] = arr[i] + prefix[i - 1];
    }

    return findMinCost(arr, 0, n - 1, prefix, memo);
}

let arr = [40, 60, 20];
console.log(minCost(arr));

Output
2400

[Expected Approach - 2] - Using Tabulation and Prefix Sum - O(n ^ 2) Time and O(n ^ 2) Space

The idea is to build a bottom‑up DP table dp[i][j] that holds the minimum cost to reduce the subarray arr[i…j] to one element. We first compute prefix sums so that any subarray sum modulo 100 can be obtained in O(1). Then, we fill dp by increasing subarray length: for each interval [i…j], we try every split point k (from i to j-1), combine the two subintervals’ costs with the merge cost (sum(i,k) * sum(k+1,j)), and take the minimum. At the end, dp[0][n-1] is the answer.

Follow the below given steps:

  • Compute a prefix array prefix of length n:
    prefix[0] = arr[0], and for i = 1…n-1,
    prefix[i] = prefix[i-1] + arr[i].
  • Create an n×n DP table dp, initialize all dp[i][i] = 0.
  • For subarray length len from 2 to n:
    • For start index i from 0 to n - len:
      • Let j = i + len - 1, and set dp[i][j] = INT_MAX.
      • For each split k from i to j - 1:
        • Compute leftCost = dp[i][k]
        • Compute rightCost = dp[k+1][j]
        • Compute mergeCost = sum(i, k, prefix) * sum(k+1, j, prefix)
        • Update dp[i][j] = min(dp[i][j], leftCost + rightCost + mergeCost)
  • Return dp[0][n-1] as the minimum total cost

Below is given the implementation:

C++
#include <bits/stdc++.h>
using namespace std;

// function to calculate the 
// sum from a[i] to a[j]
int sum(int i, int j, vector<int> &prefix) {     
    if (i == 0)
        return prefix[j] % 100;
    return (prefix[j] - prefix[i - 1]) % 100;
}

int minCost(vector<int> &arr) {
    int n = arr.size();

    // initialize the dp
    vector<vector<int>> dp(n, vector<int>(n, 0));

    // to store prefix sum
    vector<int> prefix(n);
    prefix[0] = arr[0];
    for(int i = 1; i < n; i++) {
        prefix[i] = arr[i] + prefix[i - 1];
    }

    // Filling the dp array using tabulation
    for (int len = 2; len <= n; len++) {
        for (int i = 0; i < n - len + 1; i++) {
            int j = i + len - 1;
            dp[i][j] = INT_MAX;

            for (int k = i; k < j; k++) {
                dp[i][j] = min(dp[i][j], (dp[i][k] + dp[k + 1][j] + 
                    (sum(i, k, prefix) * sum(k + 1, j, prefix))));
            }
        }
    }

    // Return the minimum sum
    return dp[0][n - 1];
}

int main() {
    vector<int> arr = {40, 60, 20};
    cout << minCost(arr);
    return 0;
}
Java
import java.util.*;

public class GfG {

    // function to calculate the 
    // sum from a[i] to a[j]
    public static int sum(int i, int j, List<Integer> prefix) {     
        if (i == 0)
            return prefix.get(j) % 100;
        return (prefix.get(j) - prefix.get(i - 1)) % 100;
    }

    public static int minCost(List<Integer> arr) {
        int n = arr.size();

        // initialize the dp
        int[][] dp = new int[n][n];

        // to store prefix sum
        List<Integer> prefix = new ArrayList<>();
        prefix.add(arr.get(0));
        for (int i = 1; i < n; i++) {
            prefix.add(arr.get(i) + prefix.get(i - 1));
        }

        // Filling the dp array using tabulation
        for (int len = 2; len <= n; len++) {
            for (int i = 0; i < n - len + 1; i++) {
                int j = i + len - 1;
                dp[i][j] = Integer.MAX_VALUE;

                for (int k = i; k < j; k++) {
                    dp[i][j] = Math.min(dp[i][j], (dp[i][k] + dp[k + 1][j] + 
                        (sum(i, k, prefix) * sum(k + 1, j, prefix))));
                }
            }
        }

        // Return the minimum sum
        return dp[0][n - 1];
    }

    public static void main(String[] args) {
        List<Integer> arr = Arrays.asList(40, 60, 20);
        System.out.print(minCost(arr));
    }
}
Python
# function to calculate the 
# sum from a[i] to a[j]
def sum(i, j, prefix):
    if i == 0:
        return prefix[j] % 100
    return (prefix[j] - prefix[i - 1]) % 100

def minCost(arr):
    n = len(arr)

    # initialize the dp
    dp = [[0] * n for _ in range(n)]

    # to store prefix sum
    prefix = [0] * n
    prefix[0] = arr[0]
    for i in range(1, n):
        prefix[i] = arr[i] + prefix[i - 1]

    # Filling the dp array using tabulation
    for len1 in range(2, n + 1):
        for i in range(0, n - len1 + 1):
            j = i + len1 - 1
            dp[i][j] = float('inf')

            for k in range(i, j):
                dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] +
                    (sum(i, k, prefix) * sum(k + 1, j, prefix)))

    # Return the minimum sum
    return dp[0][n - 1]

if __name__ == "__main__":
    arr = [40, 60, 20]
    print(minCost(arr))
C#
using System;
using System.Collections.Generic;

public class GfG {

    // function to calculate the 
    // sum from a[i] to a[j]
    public static int sum(int i, int j, List<int> prefix) {     
        if (i == 0)
            return prefix[j] % 100;
        return (prefix[j] - prefix[i - 1]) % 100;
    }

    public static int minCost(List<int> arr) {
        int n = arr.Count;

        // initialize the dp
        int[,] dp = new int[n, n];

        // to store prefix sum
        List<int> prefix = new List<int>();
        prefix.Add(arr[0]);
        for (int i = 1; i < n; i++) {
            prefix.Add(arr[i] + prefix[i - 1]);
        }

        // Filling the dp array using tabulation
        for (int len = 2; len <= n; len++) {
            for (int i = 0; i < n - len + 1; i++) {
                int j = i + len - 1;
                dp[i, j] = int.MaxValue;

                for (int k = i; k < j; k++) {
                    dp[i, j] = Math.Min(dp[i, j], dp[i, k] + dp[k + 1, j] + 
                        (sum(i, k, prefix) * sum(k + 1, j, prefix)));
                }
            }
        }

        // Return the minimum sum
        return dp[0, n - 1];
    }

    public static void Main() {
        List<int> arr = new List<int> {40, 60, 20};
        Console.Write(minCost(arr));
    }
}
JavaScript
// function to calculate the 
// sum from a[i] to a[j]
function sum(i, j, prefix) {
    if (i === 0)
        return prefix[j] % 100;
    return (prefix[j] - prefix[i - 1]) % 100;
}

function minCost(arr) {
    let n = arr.length;

    // initialize the dp
    let dp = Array.from({ length: n }, () => Array(n).fill(0));

    // to store prefix sum
    let prefix = new Array(n);
    prefix[0] = arr[0];
    for (let i = 1; i < n; i++) {
        prefix[i] = arr[i] + prefix[i - 1];
    }

    // Filling the dp array using tabulation
    for (let len = 2; len <= n; len++) {
        for (let i = 0; i < n - len + 1; i++) {
            let j = i + len - 1;
            dp[i][j] = Number.MAX_SAFE_INTEGER;

            for (let k = i; k < j; k++) {
                dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[k + 1][j] +
                    (sum(i, k, prefix) * sum(k + 1, j, prefix)));
            }
        }
    }

    // Return the minimum sum
    return dp[0][n - 1];
}

let arr = [40, 60, 20];
console.log(minCost(arr));

Output
2400

Next Article
Article Tags :
Practice Tags :

Similar Reads