diff --git a/problems/3691-maximum-total-subarray-value-ii/analysis.md b/problems/3691-maximum-total-subarray-value-ii/analysis.md new file mode 100644 index 0000000..dfbdcb4 --- /dev/null +++ b/problems/3691-maximum-total-subarray-value-ii/analysis.md @@ -0,0 +1,102 @@ +# 3691. Maximum Total Subarray Value II + +[LeetCode Link](https://leetcode.com/problems/maximum-total-subarray-value-ii/) + +Difficulty: Hard +Topics: Array, Greedy, Segment Tree, Heap (Priority Queue) +Acceptance Rate: 28.9% + +This is a genuinely hard problem — the greedy insight is short, but turning it into something +that runs within the `n <= 5·10^4` limit takes a careful counting argument. Don't be discouraged +if the path to an efficient solution isn't obvious; work through the hints in order. + +## Hints + +### Hint 1 + +Since every subarray's value `max - min` is non-negative and we want the **maximum** total over +exactly `k` *distinct* subarrays, distinctness never forces us to take a smaller value when a +larger one is available. So the task reduces to a clean one: **sum the `k` largest values** among +all `O(n^2)` subarrays. There are far too many subarrays to list them, so think about how you'd +find the top `k` of a huge implicit multiset *without materializing it*. + +### Hint 2 + +A classic trick for "sum of the top `k` elements of an implicit set" is to **binary search on a +threshold value `T`**. If you can quickly answer "how many subarrays have value `>= T`?", then you +can find the cutoff value where the count first drops below `k`. The monotonicity you need is real: +for a fixed left endpoint, growing the subarray to the right only makes `max - min` larger, so the +count of subarrays with value `>= T` is non-increasing in `T`. + +### Hint 3 + +Counting (and summing) subarrays by their range is easiest via the **complement**: count subarrays +whose range `max - min <= X`. That predicate is *monotone in a sliding window* — if `[l..r]` has +range `<= X`, so does any `[l'..r]` with `l' >= l`. So a two-pointer window where `left` only ever +moves right works, with two **monotonic deques** tracking the window max and min. The extra spark: +maintain not just the max/min, but the **windowed sum of subarray-maxes and subarray-mins ending at +`r`**. Each deque element owns a contiguous block of left endpoints; store that block's length so +you can update the running sums in O(1) as the window grows on the right and shrinks on the left. +That gives you both `count(range <= X)` and `sum(range <= X)` in one O(n) pass. + +## Approach + +**Reduction.** Because values are non-negative and subarrays are distinct, the answer is simply the +sum of the `k` largest values of `range(l, r) = max(nums[l..r]) - min(nums[l..r])` over all +subarrays. + +**One O(n) primitive.** Define `f(X) -> (cnt, sum)` where `cnt` is the number of subarrays with +`range <= X` and `sum` is the total of their ranges. Compute it with a sliding window `[left, r]`: + +- Two monotonic deques hold the window's maximum and minimum. Each deque element is a *segment*: an + index `i` together with `len`, the number of left endpoints `l` for which this element is the max + (resp. min) of `nums[l..r]`. The front segment of the max deque is the maximum of the whole + window; the front of the min deque is the minimum. +- Maintain `sumMax = Σ_{l=left..r} max(nums[l..r])` and `sumMin` analogously. When `r` enters, + pop the back segments it dominates (`<=` for max, `>=` for min), accumulate their lengths, and push + `r` as a new segment of length `poppedLen + 1`, adjusting `sumMax` / `sumMin` by the segment value + times length. When `range > X`, advance `left`: drop one unit from the front segment of each deque + (subtract its value once, decrement its length, pop it if it hits 0). +- After settling the window for this `r`, add `r - left + 1` to `cnt` and `sumMax - sumMin` to `sum`. + +A single call with a huge `X` (so the window never shrinks) yields `total = n(n+1)/2` and +`totalSum = Σ range` over *all* subarrays. + +**From the primitive to the answer.** Let `geCount(T) = total - f(T-1).cnt` be the number of +subarrays with `range >= T`; it is non-increasing in `T`. Binary search for the largest `T*` with +`geCount(T*) >= k` (search range `[0, max(nums) - min(nums)]`). Then: + +- `c1 = geCount(T*+1)` subarrays have `range > T*`; all of them are in the top `k`. Their total is + `sumGE(T*+1) = totalSum - f(T*).sum`. +- Fill the remaining `k - c1` picks with subarrays of range exactly `T*`, each contributing `T*`. + +So `answer = sumGE(T*+1) + T* · (k - c1)`. + +**Why it works.** `geCount(T*) >= k > geCount(T*+1)` guarantees enough range-`T*` subarrays exist to +finish the selection, and every subarray strictly above the cutoff is included exactly once. + +**Worked example.** `nums = [4,2,5,1], k = 3`. Subarray ranges are +`{0,0,0,0,2,3,4,3,4,4}`; sorted descending the top three are `4,4,4`. Here `total = 10`, +`geCount(4) = 3 >= 3` and `geCount(5) = 0`, so `T* = 4`, `c1 = 0`, `sumGE(5) = 0`, and the answer is +`0 + 4·(3 - 0) = 12`. + +## Complexity Analysis + +Time Complexity: O(n · log V), where `V = max(nums) - min(nums)`. Each `f(X)` runs in O(n) (every +index is pushed/popped from each deque at most once), and binary search does O(log V) calls plus a +couple of extra evaluations. +Space Complexity: O(n) for the two monotonic deques. + +## Edge Cases + +- **Single element (`n = 1`).** The only subarray has range `0`; `k` must be `1` and the answer is + `0`. The window logic and the `T* = 0` branch both produce `0`. +- **All elements equal.** Every range is `0`, so the answer is `0` regardless of `k`. `T* = 0`, + `c1 = 0`, and `T*·(k - c1) = 0`. +- **`T* = 0` in general.** When fewer than `k` subarrays have a positive range, we take all positive + ones (`sumGE(1) = totalSum`) and pad with zero-range subarrays; the formula collapses to + `totalSum`. +- **Large counts overflow `int32`.** The number of subarrays can reach ~`1.25·10^9` and the running + sums reach ~`10^18`; use 64-bit integers throughout for counts, sums, and the answer. +- **`k` equal to the total number of subarrays.** Then `T* = 0` and the answer is the sum of *all* + subarray ranges, i.e. `totalSum`. diff --git a/problems/3691-maximum-total-subarray-value-ii/problem.md b/problems/3691-maximum-total-subarray-value-ii/problem.md new file mode 100644 index 0000000..7ac76bb --- /dev/null +++ b/problems/3691-maximum-total-subarray-value-ii/problem.md @@ -0,0 +1,75 @@ +--- +number: "3691" +frontend_id: "3691" +title: "Maximum Total Subarray Value II" +slug: "maximum-total-subarray-value-ii" +difficulty: "Hard" +topics: + - "Array" + - "Greedy" + - "Segment Tree" + - "Heap (Priority Queue)" +acceptance_rate: 2885.8 +is_premium: false +created_at: "2026-06-10T04:55:42.758621+00:00" +fetched_at: "2026-06-10T04:55:42.758621+00:00" +link: "https://leetcode.com/problems/maximum-total-subarray-value-ii/" +date: "2026-06-10" +--- + +# 3691. Maximum Total Subarray Value II + +You are given an integer array `nums` of length `n` and an integer `k`. + +You must select **exactly** `k` **distinct** non-empty subarrays `nums[l..r]` of `nums`. Subarrays may overlap, but the exact same subarray (same `l` and `r`) **cannot** be chosen more than once. + +The **value** of a subarray `nums[l..r]` is defined as: `max(nums[l..r]) - min(nums[l..r])`. + +The **total value** is the sum of the **values** of all chosen subarrays. + +Return the **maximum** possible total value you can achieve. + + + +**Example 1:** + +**Input:** nums = [1,3,2], k = 2 + +**Output:** 4 + +**Explanation:** + +One optimal approach is: + + * Choose `nums[0..1] = [1, 3]`. The maximum is 3 and the minimum is 1, giving a value of `3 - 1 = 2`. + * Choose `nums[0..2] = [1, 3, 2]`. The maximum is still 3 and the minimum is still 1, so the value is also `3 - 1 = 2`. + + + +Adding these gives `2 + 2 = 4`. + +**Example 2:** + +**Input:** nums = [4,2,5,1], k = 3 + +**Output:** 12 + +**Explanation:** + +One optimal approach is: + + * Choose `nums[0..3] = [4, 2, 5, 1]`. The maximum is 5 and the minimum is 1, giving a value of `5 - 1 = 4`. + * Choose `nums[1..3] = [2, 5, 1]`. The maximum is 5 and the minimum is 1, so the value is also `4`. + * Choose `nums[2..3] = [5, 1]`. The maximum is 5 and the minimum is 1, so the value is again `4`. + + + +Adding these gives `4 + 4 + 4 = 12`. + + + +**Constraints:** + + * `1 <= n == nums.length <= 5 * 10​​​​​​​4` + * `0 <= nums[i] <= 109` + * `1 <= k <= min(105, n * (n + 1) / 2)` diff --git a/problems/3691-maximum-total-subarray-value-ii/solution_daily_20260610.go b/problems/3691-maximum-total-subarray-value-ii/solution_daily_20260610.go new file mode 100644 index 0000000..81e0b72 --- /dev/null +++ b/problems/3691-maximum-total-subarray-value-ii/solution_daily_20260610.go @@ -0,0 +1,119 @@ +package main + +// 3691. Maximum Total Subarray Value II +// +// Approach: The answer is the sum of the k largest subarray "values", where the +// value of nums[l..r] is max - min (all values are non-negative and subarrays +// must be distinct, so distinctness never forces a smaller pick). +// +// We binary search a cutoff range value T. For a threshold X we compute, in a +// single O(n) sliding-window pass, both the number of subarrays whose range +// (max-min) is <= X and the sum of those ranges. Two monotonic deques track the +// window max and min; each deque element owns a contiguous block of left +// endpoints (its segment length), which lets us maintain the windowed sum of +// subarray-maxes and subarray-mins in O(1) per step. From count(<=X)/sum(<=X) +// we derive count(>=T)/sum(>=T) and assemble the top-k total. +// +// Time: O(n log V), Space: O(n). +func maxTotalValue(nums []int, k int) int64 { + n := len(nums) + total := int64(n) * int64(n+1) / 2 + + type seg struct { + idx int + ln int64 + } + + // rangeCountSumLE returns (cnt, sum): the number of subarrays whose + // (max-min) <= X, and the total of their (max-min) values. + rangeCountSumLE := func(X int64) (int64, int64) { + var maxDq, minDq []seg + var sumMax, sumMin int64 + var cnt, sum int64 + left := 0 + for r := 0; r < n; r++ { + v := nums[r] + + // Extend the max deque: r absorbs every back segment it dominates. + var pLen int64 = 0 + for len(maxDq) > 0 && nums[maxDq[len(maxDq)-1].idx] <= v { + e := maxDq[len(maxDq)-1] + maxDq = maxDq[:len(maxDq)-1] + sumMax -= int64(nums[e.idx]) * e.ln + pLen += e.ln + } + maxDq = append(maxDq, seg{r, pLen + 1}) + sumMax += int64(v) * (pLen + 1) + + // Extend the min deque symmetrically. + pLen = 0 + for len(minDq) > 0 && nums[minDq[len(minDq)-1].idx] >= v { + e := minDq[len(minDq)-1] + minDq = minDq[:len(minDq)-1] + sumMin -= int64(nums[e.idx]) * e.ln + pLen += e.ln + } + minDq = append(minDq, seg{r, pLen + 1}) + sumMin += int64(v) * (pLen + 1) + + // Shrink from the left while the window range exceeds X. + for int64(nums[maxDq[0].idx]-nums[minDq[0].idx]) > X { + sumMax -= int64(nums[maxDq[0].idx]) + maxDq[0].ln-- + if maxDq[0].ln == 0 { + maxDq = maxDq[1:] + } + sumMin -= int64(nums[minDq[0].idx]) + minDq[0].ln-- + if minDq[0].ln == 0 { + minDq = minDq[1:] + } + left++ + } + + cnt += int64(r - left + 1) + sum += sumMax - sumMin + } + return cnt, sum + } + + // totalSum: a window that never shrinks (X larger than any possible range). + _, totalSum := rangeCountSumLE(int64(1) << 62) + + // geCount(T): number of subarrays with range >= T. + geCount := func(T int64) int64 { + if T <= 0 { + return total + } + c, _ := rangeCountSumLE(T - 1) + return total - c + } + + mx, mn := nums[0], nums[0] + for _, x := range nums { + if x > mx { + mx = x + } + if x < mn { + mn = x + } + } + + // Largest T with geCount(T) >= k. + lo, hi := int64(0), int64(mx-mn) + for lo < hi { + mid := (lo + hi + 1) / 2 + if geCount(mid) >= int64(k) { + lo = mid + } else { + hi = mid - 1 + } + } + tStar := lo + + cLE, sLE := rangeCountSumLE(tStar) // subarrays with range <= tStar + c1 := total - cLE // subarrays with range >= tStar+1 + sumGE := totalSum - sLE // sum of ranges >= tStar+1 + + return sumGE + tStar*(int64(k)-c1) +} diff --git a/problems/3691-maximum-total-subarray-value-ii/solution_daily_20260610_test.go b/problems/3691-maximum-total-subarray-value-ii/solution_daily_20260610_test.go new file mode 100644 index 0000000..5e8c85b --- /dev/null +++ b/problems/3691-maximum-total-subarray-value-ii/solution_daily_20260610_test.go @@ -0,0 +1,30 @@ +package main + +import "testing" + +func TestSolution(t *testing.T) { + tests := []struct { + name string + nums []int + k int + expected int64 + }{ + {"example 1: pick two overlapping subarrays", []int{1, 3, 2}, 2, 4}, + {"example 2: three subarrays each value 4", []int{4, 2, 5, 1}, 3, 12}, + {"edge case: single element forces value 0", []int{7}, 1, 0}, + {"edge case: all equal elements yield 0", []int{5, 5, 5, 5}, 4, 0}, + {"edge case: k equals total subarrays sums all ranges", []int{1, 3, 2}, 6, 5}, + {"edge case: two elements single pick", []int{0, 1000000000}, 1, 1000000000}, + {"edge case: pick only the single largest range", []int{4, 2, 5, 1}, 1, 4}, + {"edge case: strictly increasing array", []int{1, 2, 3, 4}, 3, 7}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := maxTotalValue(tt.nums, tt.k) + if got != tt.expected { + t.Errorf("maxTotalValue(%v, %d) = %d, want %d", tt.nums, tt.k, got, tt.expected) + } + }) + } +}