For each possible subarray, compute its sum and check if it is odd. We try every starting index and extend to every possible ending index, accumulating the sum incrementally.
i, initialize a running sum.n-1.res if so.We use memoization to count subarrays ending at each position. For a subarray starting at index i, the parity of its sum depends on the running parity as we extend rightward. By caching results for each (index, parity) state, we avoid redundant calculations.
dfs(i, parity) returning the count of odd-sum subarrays starting at index i with the given running parity.1 to the count if the new parity is odd, then recurse to the next index.dfs(i, 0) for all starting indices to get the total.class Solution:
def numOfSubarrays(self, arr: List[int]) -> int:
mod = 10**9 + 7
n = len(arr)
memo = {}
def dp(i: int, parity: int) -> int:
if i == n:
return 0
if (i, parity) in memo:
return memo[(i, parity)]
new_parity = (parity + arr[i]) % 2
res = new_parity + dp(i + 1, new_parity)
memo[(i, parity)] = res % mod
return memo[(i, parity)]
ans = 0
for i in range(n):
ans = (ans + dp(i, 0)) % mod
return ansWe can convert the top-down approach to bottom-up by processing indices from right to left. For each position, we compute how many odd-sum subarrays can be formed starting there, given either even or odd running parity.
dp[i][parity] representing counts from index i with given parity.dp value.dp[i][0] for all indices to get the final answer.class Solution:
def numOfSubarrays(self, arr: List[int]) -> int:
n = len(arr)
mod = 10**9 + 7
dp = [[0] * 2 for _ in range(n + 1)]
for i in range(n - 1, -1, -1):
for parity in range(2):
new_parity = (parity + arr[i]) % 2
dp[i][parity] = (new_parity + dp[i + 1][new_parity]) % mod
res = 0
for i in range(n):
res = (res + dp[i][0]) % mod
return resA subarray has an odd sum when its prefix sum parity differs from the prefix sum at its starting point. If the current prefix sum is odd, pairing it with any previous even prefix sum yields an odd subarray. We track counts of odd and even prefix sums seen so far.
1 (for the subarray from the start) plus the count of previous even prefix sums.res.class Solution:
def numOfSubarrays(self, arr: List[int]) -> int:
cur_sum = odd_cnt = even_cnt = res = 0
MOD = 10**9 + 7
for n in arr:
cur_sum += n
if cur_sum % 2:
res = (res + 1 + even_cnt) % MOD
odd_cnt += 1
else:
res = (res + odd_cnt) % MOD
even_cnt += 1
return resWe only need to track the parity of the prefix sum (0 for even, 1 for odd). A count array of size 2 stores how many prefix sums of each parity we have seen. For each new element, we look up the count of the opposite parity to find valid subarrays.
count[0] = 1 to represent the empty prefix (sum 0, which is even).2.count[1 - prefix] to the result (subarrays ending here with odd sum).count[prefix] and continue.When using the prefix sum approach, the empty prefix (sum of zero elements) has an even sum. If you forget to initialize count[0] = 1 or evenCnt = 0 with proper handling, you will miss subarrays that start from index 0.
The key insight is that odd - even = odd and even - odd = odd. Some programmers mistakenly check if the current prefix sum is odd and then add the count of odd prefix sums, when they should be adding the count of even prefix sums (since subtracting an even prefix from an odd prefix yields an odd subarray sum).
The result can grow very large, so modulo 10^9 + 7 must be applied. A common mistake is applying modulo only at the end instead of during each addition, which can cause integer overflow in languages without arbitrary precision integers.