# Sum of Total Strength of Wizards

Published: Sep 14, 2022

Hard Monotonic Stack Prefix Sum Array

## Introduction

This can be solved using monotonic stack and prefix sum. However, this is really a hard problem. It need from left and right monotonic stacks. The prefix sum is a doubly calculated prefix sum. The way to summing up prefix sum is not straightforward.

## Problem Description

As the ruler of a kingdom, you have an army of wizards at your command. You are given a 0-indexed integer array `strength`, where `strength[i]` denotes the strength of the ith wizard. For a contiguous group of wizards (i.e. the wizards’ strengths form a subarray of strength), the total strength is defined as the product of the following two values:

• The strength of the weakest wizard in the group.
• The total of all the individual strengths of the wizards in the group.

Return the sum of the total strengths of all contiguous groups of wizards. Since the answer may be very large, return it `modulo 10**9 + 7`.

A subarray is a contiguous non-empty sequence of elements within an array.

Constraints:

• `1 <= strength.length <= 10**5`
• `1 <= strength[i] <= 10**9`

https://leetcode.com/problems/sum-of-total-strength-of-wizards/

## Examples

``````Example 1:
Input: strength = [1,3,1,2]
Output: 44
Explanation:
subarrays: [1], [1,3], [1,3,1], [1,3,1,2], [3], [3,1], [3,1,2], [1], [1,2], [2]
min(subarray) * sum(subarray): 1, 4, 5, 7, 9, 4, 6, 1, 3, 4
total = 44
``````
``````Example 2:
Input: strength = [5,4,6]
Output: 213
Explanation:
``````

## Analysis

For the first step, create monotonically increasing stacks from left and right. Next step is to calculate prefix sum. It is a prefix sum of prefix sum. Here, the solution uses Python’s `itertools.accumulate` function. Lastly, total strength is calculated using prefix sum with the range.

## Solution

``````class SumOfTotalStrengthOfWizards:
def totalStrength(self, strength: List[int]) -> int:
mod = 10 ** 9 + 7
n = len(strength)
# next small on the right
stack, right = [], [n for _ in range(n)]
for i in range(n):
while stack and strength[stack[-1]] > strength[i]:
right[stack.pop()] = i
stack.append(i)
# next small on the left
stack, left = [], [-1 for _ in range(n)]
for i in range(n - 1, -1, -1):
while stack and strength[stack[-1]] >= strength[i]:
left[stack.pop()] = i
stack.append(i)
result = 0
prefix = list(accumulate(accumulate(strength), initial=0))
for i in range(n):
l, r = left[i], right[i]
l_pre = prefix[i] - prefix[max(l, 0)]
r_pre = prefix[r] - prefix[i]
result += strength[i] * (r_pre * (i - l) - l_pre * (r - i)) % mod
return result % mod
``````

## Complexities

• Time: `O(n)`
• Space: `O(n)`