Skip to content
Related Articles

Related Articles

Improve Article

Sum of maximum of all subarrays by adding even frequent maximum twice

  • Last Updated : 30 Jun, 2021
Geek Week

Given an array arr[] consisting of N integers (All array elements are a perfect power of 2), the task is to calculate the sum of the maximum elements in all the subarrays

Note: If the frequency of the maximum element in a subarray is even, add twice the value of that element to the sum.

Examples:

Input: arr[] = {1, 2}
Output: 5
Explanation: All possible subarrays are {1}, {1, 2}, {2}. 
Subarray 1: {1}. Maximum = 1. Sum = 1.
Subarray 2: {1, 2}. Maximum = 2. Sum = 3.
Subarray 3: {2}. Maximum = 2.Sum = 5.
Therefore, required output is 5.

Input: arr[] = {4, 4}
Output: 16
Explanation: All possible subarrays are {4}, {4, 4}, {4}.
Subarray 1: {4}. Maximum = 4. Sum = 1.
Subarray 2: {4, 4}. Maximum = 4. Since the maximum occurs twice in the subarray, Sum = 4 + 8 = 12.
Subarray 3: {4}. Maximum = 4. Sum = 16.
Therefore, required output is 16.

Naive Approach: The simplest approach to solve this problem is to generate all possible subarrays of the given array and find the maximum element in all subarrays along with the count of their occurrences. Finally, print the sum of all the maximum elements obtained. Follow the steps below to solve the problem:



Below is the implementation of the above approach:

C++




// C++ program for the above approach
#include<bits/stdc++.h>
using namespace std;
 
// Function to calculate sum of
// maximum of all subarrays
void findSum(vector<int>a)
{
    // Storeas the sum of maximums
    int ans = 0;
 
    // Traverse the array
    for(int low = 0;
            low < a.size();
            low++)
    {
        for(int high = low;
                high < a.size();
                high++)
        {
             
            // Store the frequency of the
            // maximum element in subarray
            int count = 0;
            int maxNumber = 0;
 
            // Finding maximum
            for(int i = low;
                    i <= high; i++)
            {
                 
                // Increment frequency by 1
                if (a[i] == maxNumber)
                    count++;
 
                // If new maximum is obtained
                else if (a[i] > maxNumber)
                {
                    maxNumber = a[i];
                    count = 1;
                }
            }
 
            // If frequency of maximum
            // is even, then add 2*maxNumber.
            // Otherwise, add maxNumber
            ans += maxNumber * ((count % 2 == 0) ? 2 : 1);
        }
    }
 
    // Print the sum obtained
    cout << (ans);
}
 
// Driver Code
int main()
{
    vector<int>arr = { 2, 1, 4, 4, 2 };
     
    // Function Call
    findSum(arr);
}
 
// This code is contributed by amreshkumar3

Java




// Java program for the above approach
 
import java.io.*;
 
class GFG {
 
    // Function to calculate sum of
    // maximum of all subarrays
    public static void findSum(int a[])
    {
        // Stores the sum of maximums
        int ans = 0;
 
        // Traverse the array
        for (int low = 0;
             low < a.length; low++) {
 
            for (int high = low;
                 high < a.length;
                 high++) {
 
                // Store the frequency of the
                // maximum element in subarray
                int count = 0;
                int maxNumber = 0;
 
                // Finding maximum
                for (int i = low;
                     i <= high; i++) {
 
                    // Increment frequency by 1
                    if (a[i] == maxNumber)
                        count++;
 
                    // If new maximum is obtained
                    else if (a[i] > maxNumber) {
                        maxNumber = a[i];
                        count = 1;
                    }
                }
 
                // If frequency of maximum
                // is even, then add 2*maxNumber.
                // Otherwise, add maxNumber
                ans += maxNumber
                       * ((count % 2 == 0) ? 2 : 1);
            }
        }
 
        // Print the sum obtained
        System.out.println(ans);
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        int[] arr = { 2, 1, 4, 4, 2 };
 
        // Function Call
        findSum(arr);
    }
}

Python3




# Python3 program for the above approach
 
# Function to calculate sum of
# maximum of all subarrays
def findSum(a):
     
  # Stores the sum of maximums
  ans = 0
   
  # Traverse the array
  for low in range(0, len(a)):
    for high in range(low,len(a)):
         
      # Store the frequency of the
      # maximum element in subarray
      count = 0
      maxNumber = 0
       
      # Finding maximum
      for i in range(low, high + 1):
           
        # Increment frequency by 1
        if (a[i] == maxNumber):
          count += 1
           
        # If new maximum is obtained
        elif (a[i] > maxNumber):
          maxNumber = a[i]
          count = 1
 
      # If frequency of maximum
      # is even, then add 2*maxNumber.
      # Otherwise, add maxNumber
      if count % 2:
        ans += maxNumber
      else:
        ans += maxNumber * 2
         
  # Print the sum obtained
  print(ans)
     
# Driver Code
arr = [ 2, 1, 4, 4, 2 ]
 
# Function Call
findSum(arr)
 
# This code is contributed by rohitsingh07052

C#




// C# program for the above approach
using System;
 
class GFG {
 
  // Function to calculate sum of
  // maximum of all subarrays
  public static void findSum(int[] a)
  {
     
    // Stores the sum of maximums
    int ans = 0;
 
    // Traverse the array
    for (int low = 0; low < a.Length; low++) {
 
      for (int high = low; high < a.Length; high++) {
 
        // Store the frequency of the
        // maximum element in subarray
        int count = 0;
        int maxNumber = 0;
 
        // Finding maximum
        for (int i = low; i <= high; i++) {
 
          // Increment frequency by 1
          if (a[i] == maxNumber)
            count++;
 
          // If new maximum is obtained
          else if (a[i] > maxNumber) {
            maxNumber = a[i];
            count = 1;
          }
        }
 
        // If frequency of maximum
        // is even, then add 2*maxNumber.
        // Otherwise, add maxNumber
        ans += maxNumber
          * ((count % 2 == 0) ? 2 : 1);
      }
    }
 
    // Print the sum obtained
    Console.WriteLine(ans);
  }
 
  // Driver Code
  public static void Main()
  {
    int[] arr = { 2, 1, 4, 4, 2 };
 
    // Function Call
    findSum(arr);
  }
}
 
// This code is contributed by ukasp.

Javascript




<script>
 
      // JavaScript program for the above approach
       
      // Function to calculate sum of
      // maximum of all subarrays
      function findSum(a) {
      // Stores the sum of maximums
        var ans = 0;
 
        // Traverse the array
        for (var low = 0; low < a.length; low++) {
          for (var high = low; high < a.length; high++) {
            // Store the frequency of the
            // maximum element in subarray
            var count = 0;
            var maxNumber = 0;
 
            // Finding maximum
            for (var i = low; i <= high; i++) {
              // Increment frequency by 1
              if (a[i] === maxNumber) count++;
              // If new maximum is obtained
              else if (a[i] > maxNumber) {
                maxNumber = a[i];
                count = 1;
              }
            }
 
            // If frequency of maximum
            // is even, then add 2*maxNumber.
            // Otherwise, add maxNumber
            ans += maxNumber * (count % 2 === 0 ? 2 : 1);
          }
        }
 
        // Print the sum obtained
        document.write(ans);
      }
 
      // Driver Code
      var arr = [2, 1, 4, 4, 2];
 
      // Function Call
      findSum(arr);
       
</script>
Output: 
75

 

Time Complexity: O(N3)
Auxiliary Space: O(1)

Optimized Approach: To optimize the above approach, the idea is to store the prefix sums of every bit of array elements and find the frequency of the largest element in a subarray in O(1) computational complexity. This approach works as all the array elements are powers of 2.

Below is the implementation of the above approach:

Java




// Java program for the above approach
import java.io.*;
 
class GFG {
 
    // Function to calculate sum of
    // maximum of all subarrays
    public static void findSum(int a[])
    {
        // Calculate prefix sum array
        int[][] prefixSums
            = getPrefixSums(a);
 
        // Store the sum of maximums
        int ans = 0;
 
        // Traverse the array
        for (int low = 0;
             low < a.length;
             low++) {
 
            for (int high = low;
                 high < a.length;
                 high++) {
 
                // Store the frequency of the
                // maximum element in subarray
                int count = 0;
                int maxNumber = 0;
 
                // Store prefix sum of every bit
                for (int i = 30; i >= 0; i--) {
 
                    // Get the frequency of the
                    // largest element in subarray
                    count = getCountLargestNumber(
                        low, high, i, prefixSums);
 
                    if (count > 0) {
                        maxNumber = (1 << i);
 
                        // If frequency of the largest
                        // element is even, add 2 * maxNumber
                        // Otherwise, add maxNumber
                        ans += maxNumber
                               * ((count % 2 == 0) ? 2 : 1);
                        break;
                    }
                }
            }
        }
 
        // Print the required answer
        System.out.println(ans);
    }
 
    // Function to calculate the prefix
    // sum array
    public static int[][] getPrefixSums(
        int[] a)
    {
 
        // Initialize prefix array
        int[][] prefix = new int[32][a.length + 1];
 
        // Start traversing the array
        for (int j = 0; j < a.length; j++) {
 
            // Update the prefix array for
            // each element in the array
            for (int i = 0; i <= 30; i++) {
 
                // To check which bit is set
                int mask = (1 << i);
                prefix[i][j + 1] += prefix[i][j];
                if ((a[j] & mask) > 0)
                    prefix[i][j + 1]++;
            }
        }
 
        // Return prefix array
        return prefix;
    }
 
    // Function to find the maximum
    // in subarray {arr[low], ..., arr[high]}
    public static int
    getCountLargestNumber(
        int low, int high, int i,
        int[][] prefixSums)
    {
        return prefixSums[i][high + 1]
            - prefixSums[i][low];
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        int[] arr = { 2, 1, 4, 4, 2 };
 
        // Function Call
        findSum(arr);
    }
}
Output: 
75

 

Time Complexity: O(N2)
Auxiliary Space: O(32 * N)

Efficient Approach: To optimize the above approach, the idea is to use the property that all the array elements are powers of 2, and leverage that property to solve the problem. Follow the steps below to solve the problem:

  • Iterate through all powers of 2 in descending order. Consider any arbitrary power of 2 as a mask.
  • Divide the array into subarrays such that no subarray will contain arr[index] = -1, where an index is any valid position in the array.
  • Let the subarray obtained from the above step be S. Traverse through S and add the values contributed by only the subarrays in S, which have the current mask, from the outer loop. Also set the corresponding position, where arr[index] = mask, to arr[index] = -1.
  • To calculate the values contributed by all the subarrays in S that contains the mask and maintain three counters as oddCount, eventCount, and the frequency of mask.
  • The pointer prev points to the previous index, such that arr[prev] = mask.
  • At any index, where arr[index] = mask, get the count of integers between the last occurrence of the mask and the current occurrence by subtracting prev from the index. Use this count and the parity of frequency of mask, to get the values contributed by all contiguous subarrays that contain a mask, using the formula count = (index – prev) and add the count to the answer.
  • If the frequency of the maximum is even or odd and if the parity is odd:
    • Values contributed by all the contiguous subarrays that have the frequency of mask as odd is (count – 1)*evenCount + oddCount.
    • Values contributed by all the contiguous subarrays that have the frequency of mask as even is 2*(count – 1)*oddCount + 2*evenCount.
  • Otherwise, if the parity is even:
    • Values contributed by all the contiguous subarrays that have the frequency of mask as odd is (count – 1)*oddCount + evenCount.
    • Values contributed by all the contiguous subarrays that have the frequency of mask as even is 2*(count – 1) * evenCount + 2 * oddCount.
  • Add all the corresponding values to the answer. Also add the count to evenCount if parity is even. Otherwise, add count to oddCount.

Below is the implementation of the above approach:

Java




// Java program for the above approach
import java.io.*;
 
class GFG {
 
    // Function to calculate sum of
    // maximum of all subarrays
    public static void findSum(int a[])
    {
        int ans = 0;
        int prev = -1;
 
        // Iterate over the range [30, 0]
        for (int i = 30; i >= 0; i--) {
            int mask = (1 << i);
 
            // Inner loop through the
            // length of the array
            for (int j = 0;
                 j < a.length; j++) {
 
                // Divide the array such
                // that no subarray will
                // have any index set to -1
                if (a[j] == -1) {
                    ans += findSumOfValuesOfRange(
                        a, prev + 1, j - 1, mask);
                    prev = j;
                }
            }
 
            // Find the sum of subarray
            ans += findSumOfValuesOfRange(
                a, prev + 1, a.length - 1, mask);
        }
 
        // Print the sum obtained
        System.out.println(ans);
    }
 
    // Function that takes any subarray
    // S and return values contributed
    // by only the subarrays in S containing mask
    public static int findSumOfValuesOfRange(
        int[] a, int low, int high, int mask)
    {
        if (low > high)
            return 0;
 
        // Stores count even, odd count of
        // occurrences and maximum element
        int evenCount = 0, oddCount = 0,
            countLargestNumber = 0;
        int prev = low - 1, ans = 0;
 
        // Traverse from low to high
        for (int i = low; i <= high; i++) {
 
            // Checking if this position
            // in the array is mask
            if ((mask & a[i]) > 0) {
 
                // Mask is the largest
                // number in subarray.
                // Increment count by 1
                countLargestNumber++;
 
                // Store parity as 0 or 1
                int parity = countLargestNumber % 2;
 
                // Setting a[i]=-1, this
                // will help in splitting
                // array into subarrays
                a[i] = -1;
                int count = i - prev;
                ans += count;
 
                // Add values contributed
                // by those subarrays that
                // have an odd frequency
                ans += (count - 1)
                       * ((parity == 1) ? evenCount
                                        : oddCount);
                ans += ((parity == 1) ? oddCount
                                      : evenCount);
 
                // Adding values contributed
                // by those subarrays that
                // have an even frequency
                ans += 2 * (count - 1)
                       * ((parity == 1) ? oddCount
                                        : evenCount);
                ans += 2
                       * ((parity == 1) ? evenCount
                                        : oddCount);
 
                // Set the prev pointer
                // to this position
                prev = i;
 
                if (parity == 1)
                    oddCount += count;
                else
                    evenCount += count;
            }
        }
 
        if (prev != low - 1) {
            int count = high - prev;
            int parity = countLargestNumber % 2;
 
            ans += count
                   * ((parity == 1)
                          ? oddCount
                          : evenCount);
            ans += 2 * count
                   * ((parity == 1)
                          ? evenCount
                          : oddCount);
            ans *= mask;
        }
 
        // Return the final sum
        return ans;
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        int[] arr = { 2, 1, 4, 4, 2 };
 
        // Function call
        findSum(arr);
    }
}
Output: 
75

 

Time Complexity: O(30*N)
Auxiliary Space: O(1)

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with experts, please refer DSA Live Classes for Working Professionals and Competitive Programming Live for Students.




My Personal Notes arrow_drop_up
Recommended Articles
Page :