LeetCode-in-Java

3956. Maximum Sum of M Non-Overlapping Subarrays I

Hard

You are given an integer array nums of length n, and three integers m, l, and r.

Your task is to select at least one and at most m non-overlapping non-empty subarrays from nums such that:

Return the maximum total sum you can achieve.

Example 1:

Input: nums = [4,1,-5,2], m = 2, l = 1, r = 3

Output: 7

Explanation:

One optimal strategy is to:

Example 2:

Input: nums = [1,0,3,4], m = 2, l = 1, r = 2

Output: 8

Explanation:

One optimal strategy is to:

Example 3:

Input: nums = [-1,7,-4], m = 1, l = 2, r = 3

Output: 6

Explanation:

Example 4:

Input: nums = [-3,-4,-1], m = 2, l = 1, r = 2

Output: -1

Explanation:

Constraints:

Solution

public class Solution {
    public long maximumSum(int[] nums, int m, int l, int r) {
        int n = nums.length;
        long[] pre = new long[n + 1];
        for (int i = 0; i < n; i++) {
            pre[i + 1] = pre[i] + nums[i];
        }
        long neg = -(long) 4e18;
        long[] prev = new long[n + 1];
        for (int i = 0; i <= n; i++) {
            prev[i] = 0;
        }
        long res = neg;
        for (int t = 1; t <= m; t++) {
            long[] curr = new long[n + 1];
            for (int i = 0; i <= n; i++) {
                curr[i] = neg;
            }
            int[] dq = new int[n + 1];
            int head = 0;
            int tail = 0;
            for (int i = 1; i <= n; i++) {
                curr[i] = curr[i - 1];
                int add = i - l;
                if (add >= 0 && prev[add] != neg) {
                    long val = prev[add] - pre[add];
                    while (head < tail) {
                        int idx = dq[tail - 1];
                        long last = prev[idx] - pre[idx];
                        if (last <= val) {
                            tail--;
                        } else {
                            break;
                        }
                    }
                    dq[tail++] = add;
                }
                int left = i - r;
                while (head < tail && dq[head] < left) {
                    head++;
                }
                if (head < tail) {
                    int s = dq[head];
                    curr[i] = Math.max(curr[i], pre[i] + prev[s] - pre[s]);
                }
            }
            res = Math.max(res, curr[n]);
            prev = curr;
        }
        return res;
    }
}