Range Sum of Sorted Subarray Sums
Generate all subarray sums, sort, and sum the requested index range modulo 1e9+7.
4 min read
sorting prefix-sum
Problem#
Given an array nums of length n, enumerate the sums of all n*(n+1)/2 non-empty contiguous subarrays. Sort them, and return the sum of values from index left to right inclusive (1-indexed), modulo 10^9 + 7.
Examples#
nums = [1,2,3,4], n = 4, left = 1, right = 5→13nums = [1,2,3,4], n = 4, left = 3, right = 4→6nums = [1,2,3,4], n = 4, left = 1, right = 10→50
Constraints#
1 <= nums.length <= 1000,1 <= nums[i] <= 100,1 <= left <= right <= n * (n + 1) / 2.
Approach#
There are at most ~500500 subarray sums. Compute them in O(n^2) with running totals, sort once, then sum the range.
Solution#
class Solution {public: int rangeSum(vector<int>& nums, int n, int left, int right) { const int MOD = 1'000'000'007; vector<int> sums; sums.reserve(n * (n + 1) / 2); for (int i = 0; i < n; ++i) { int s = 0; for (int j = i; j < n; ++j) { s += nums[j]; sums.push_back(s); } } sort(sums.begin(), sums.end()); long ans = 0; for (int i = left - 1; i < right; ++i) ans = (ans + sums[i]) % MOD; return (int)ans; }};func rangeSum(nums []int, n int, left int, right int) int { const MOD = 1_000_000_007 sums := make([]int, 0, n*(n+1)/2) for i := 0; i < n; i++ { s := 0 for j := i; j < n; j++ { s += nums[j] sums = append(sums, s) } } sort.Ints(sums) ans := 0 for i := left - 1; i < right; i++ { ans = (ans + sums[i]) % MOD } return ans}from typing import List
class Solution: def rangeSum(self, nums: List[int], n: int, left: int, right: int) -> int: MOD = 1_000_000_007 sums: List[int] = [] for i in range(n): s = 0 for j in range(i, n): s += nums[j] sums.append(s) sums.sort() ans = 0 for i in range(left - 1, right): ans = (ans + sums[i]) % MOD return ansfunction rangeSum(nums, n, left, right) { const MOD = 1_000_000_007; const sums = []; for (let i = 0; i < n; i++) { let s = 0; for (let j = i; j < n; j++) { s += nums[j]; sums.push(s); } } sums.sort((a, b) => a - b); let ans = 0; for (let i = left - 1; i < right; i++) ans = (ans + sums[i]) % MOD; return ans;}class Solution { public int rangeSum(int[] nums, int n, int left, int right) { final int MOD = 1_000_000_007; int[] sums = new int[n * (n + 1) / 2]; int idx = 0; for (int i = 0; i < n; i++) { int s = 0; for (int j = i; j < n; j++) { s += nums[j]; sums[idx++] = s; } } Arrays.sort(sums); long ans = 0; for (int i = left - 1; i < right; i++) ans = (ans + sums[i]) % MOD; return (int) ans; }}function rangeSum(nums: number[], n: number, left: number, right: number): number { const MOD = 1_000_000_007; const sums: number[] = []; for (let i = 0; i < n; i++) { let s = 0; for (let j = i; j < n; j++) { s += nums[j]; sums.push(s); } } sums.sort((a, b) => a - b); let ans = 0; for (let i = left - 1; i < right; i++) ans = (ans + sums[i]) % MOD; return ans;}Editorial#
Even at n = 1000, the sum list size is bounded by 500500 and fits in memory. Sorting and slicing is straightforward; the running prefix avoids re-summing inner subarrays.
Complexity#
- Time: O(n^2 log n).
- Space: O(n^2).
Concept revision#
Related#