3117. Minimum Sum of Values by Dividing Array
SourceWeekly Contest 393 Q4DifficultyHardRating2735
Description
You are given two arrays nums and andValues of length n and m respectively.
The value of an array is equal to the last element of that array.
You have to divide nums into m disjoint contiguous subarrays such that for the ith subarray [li, ri], the bitwise AND of the subarray elements is equal to andValues[i], in other words, nums[li] & nums[li + 1] & ... & nums[ri] == andValues[i] for all 1 <= i <= m, where & represents the bitwise AND operator.
Return the minimum possible sum of the values of the m subarrays nums is divided into. If it is not possible to divide nums into m subarrays satisfying these conditions, return -1.
Example 1:
Input: nums = [1,4,3,3,2], andValues = [0,3,3,2]
Output: 12
Explanation:
The only possible way to divide nums is:
[1,4]as1 & 4 == 0.[3]as the bitwiseANDof a single element subarray is that element itself.[3]as the bitwiseANDof a single element subarray is that element itself.[2]as the bitwiseANDof a single element subarray is that element itself.
The sum of the values for these subarrays is 4 + 3 + 3 + 2 = 12.
Example 2:
Input: nums = [2,3,5,7,7,7,5], andValues = [0,7,5]
Output: 17
Explanation:
There are three ways to divide nums:
[[2,3,5],[7,7,7],[5]]with the sum of the values5 + 7 + 5 == 17.[[2,3,5,7],[7,7],[5]]with the sum of the values7 + 7 + 5 == 19.[[2,3,5,7,7],[7],[5]]with the sum of the values7 + 7 + 5 == 19.
The minimum possible sum of the values is 17.
Example 3:
Input: nums = [1,2,3,4], andValues = [2]
Output: -1
Explanation:
The bitwise AND of the entire array nums is 0. As there is no possible way to divide nums into a single subarray to have the bitwise AND of elements 2, return -1.
Constraints:
1 <= n == nums.length <= 1041 <= m == andValues.length <= min(n, 10)1 <= nums[i] < 1050 <= andValues[j] < 105
Solutions
Solution 1: Memoization Search
Thinking
The array must be split into \(m\) segments whose AND equals \(\textit{andValues}[j]\), minimizing the sum of segment endpoints. Enumerating every cut is exponential.
AND only loses bits, so a segment can be abandoned once it drops below the target. The state (index, finished segments, running AND) is unique, and distinct AND values are \(O(\log M)\).
Memoize \(dfs(i,j,a)\): AND in \(nums[i]\), then either extend the segment or, when the AND matches the target, cut and add \(nums[i]\). Return infinity when too few elements remain or the AND undershoots.
We design a function \(dfs(i, j, a)\), which represents the possible minimum sum of subarray values that can be obtained starting from the \(i\)-th element, with \(j\) subarrays already divided, and the bitwise AND result of the current subarray to be divided is \(a\). The answer is \(dfs(0, 0, -1)\).
The execution process of the function \(dfs(i, j, a)\) is as follows:
- If \(n - i < m - j\), it means that the remaining elements are not enough to divide into \(m - j\) subarrays, return \(+\infty\).
- If \(j = m\), it means that \(m\) subarrays have been divided. At this time, check whether \(i = n\) holds. If it holds, return \(0\), otherwise return \(+\infty\).
- Otherwise, we perform a bitwise AND operation on \(a\) and \(nums[i]\) to get a new \(a\). If \(a < andValues[j]\), it means that the bitwise AND result of the current subarray to be divided does not meet the requirements, return \(+\infty\). Otherwise, we have two choices:
- Do not divide the current element, i.e., \(dfs(i + 1, j, a)\).
- Divide the current element, i.e., \(dfs(i + 1, j + 1, -1) + nums[i]\).
- Return the minimum of the above two choices.
To avoid repeated calculations, we use the method of memoization search and store the result of \(dfs(i, j, a)\) in a hash table.
The time complexity is \(O(n \times m \times \log M)\), and the space complexity is \(O(n \times m \times \log M)\). Where \(n\) and \(m\) are the lengths of the arrays \(nums\) and \(andValues\) respectively; and \(M\) is the maximum value in the array \(nums\), in this problem \(M \leq 10^5\).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | |
Solution 2: Dynamic Programming
Thinking
Split the array into \(m\) segments whose AND equals \(\textit{andValues}[j]\), and minimize the sum of the segment endpoints. \(n\) can be \(10^4\), so enumerating every cut is exponential.
The state is the index, the number of finished segments, and the running AND. Extending the current segment is always the first call, so the chain from index \(0\) to \(n\) has length \(n\). Python raises RecursionError at \(n=2000\), Java overflows at \(n=10^4\), and Node overflows at \(n=8000\).
AND only drops bits. Subarrays that end at the same index have \(O(\log M)\) distinct AND values, and the best future cost depends only on the segment index and that AND.
Walk left to right and keep one map from \((j,a)\) to the minimum cost of reaching it. \(a=-1\) means the new segment has no element yet. After absorbing \(nums[i]\), stay in segment \(j\), or, when the AND matches the target, close the segment, add \(nums[i]\), and open the next one. The last segment can close only at the end of the array.
Scan the array from left to right and keep only the current layer. State \((j, a)\) means \(j\) segments are finished and the AND of the open segment, before absorbing the next element, is \(a\). Its value is the minimum sum of segment endpoints used to reach it. \(a = -1\) means the open segment is empty. The only initial state is \((0, -1)\) with cost \(0\). The answer is the cost of \((m, -1)\) after the whole array has been scanned.
When handling \(nums[i]\), consider every state \((j, a)\):
- If \(n - i < m - j\), too few elements remain for \(m - j\) segments, so drop the state.
- Let \(a'\) be the bitwise AND of \(a\) and \(nums[i]\). The empty value \(-1\) AND any number is that number itself. If \(a' < \textit{andValues}[j]\), later ANDs can only get smaller and can no longer hit the target, so drop the state.
- Otherwise \(nums[i]\) can stay in the current segment. Move to \((j, a')\) with the same cost.
- If \(a' = \textit{andValues}[j]\), the current segment can also end at index \(i\), adding \(nums[i]\) to the cost. When \(j + 1 < m\), the new state is \((j + 1, -1)\). When \(j + 1 = m\), the division covers the array only if \(i = n - 1\), and that state is \((m, -1)\).
Keep the smaller cost for the same state. If \((m, -1)\) is absent, return \(-1\).
The time complexity is \(O(n \times m \times \log M)\), and the space complexity is \(O(m \times \log M)\). Here \(n\) and \(m\) are the lengths of \(nums\) and \(andValues\), and \(M\) is the maximum value in \(nums\), with \(M \leq 10^5\) in this problem. Subarray ANDs that share a right endpoint change at most \(O(\log M)\) times, so each layer has \(O(m \times \log M)\) states.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | |