#Dynamic Programming #prefix sum #누적합
초기값 (i = 0) :
dp[0][0]=1, dp[0][1]=0dp[0][0]=0, dp[0][1]=1전이 (i ≥ 1) :
dp[i][0] = dp[i−1][0]+1dp[i][1] = dp[i−1][1]class Solution {
public int numOfSubarrays(int[] arr) {
int mod = 1_000_000_007;
int n = arr.length;
// dp[i][0] : i번째까지 고려할 때, i에서 끝나는 부분 배열 중 짝수 합의 개수
// dp[i][1] : i번째까지 고려할 때, i에서 끝나는 부분 배열 중 홀수 합의 개수
int[][] dp = new int[n][2];
// 초기값 설정
if (arr[0] % 2 == 0) {
dp[0][0] = 1;
dp[0][1] = 0;
} else {
dp[0][0] = 0;
dp[0][1] = 1;
}
int ans = dp[0][1]; // 첫 번째 원소에 대해 홀수이면 더함
// 점화식에 따라 dp 배열 채우기
for (int i = 1; i < n; i++) {
if (arr[i] % 2 == 0) {
// 현재 원소가 짝수: 합의 홀짝이 바뀌지 않음
dp[i][0] = (dp[i-1][0] + 1) % mod;
dp[i][1] = dp[i-1][1];
} else {
// 현재 원소가 홀수: 홀수와 짝수의 역할이 교환됨
dp[i][0] = dp[i-1][1];
dp[i][1] = (dp[i-1][0] + 1) % mod;
}
ans = (ans + dp[i][1]) % mod;
}
return ans;
}
}
즉, 홀수 부분 배열의 개수 = (짝수인 prefix sum의 개수 × 홀수인 prefix sum의 개수)
두 prefix의 홀짝이 다르면 해당 부분 배열의 합이 홀수가 됨을 이용하여, 지금까지 등장한 짝수 prefix와 홀수 prefix의 개수를 곱하는 방식(누적합)을 사용합니다.
class Solution {
public int numOfSubarrays(int[] arr) {
int mod = 1_000_000_007;
long evenCount = 1; // 초기 prefix sum 0 (짝수) 한 개
long oddCount = 0;
long prefix = 0;
long ans = 0;
for (int num : arr) {
prefix += num;
if (prefix % 2 == 0) {
// 현재 prefix가 짝수이면, 이전 홀수 prefix와의 차가 홀수임
ans = (ans + oddCount) % mod;
evenCount++;
} else {
// 현재 prefix가 홀수이면, 이전 짝수 prefix와의 차가 홀수임
ans = (ans + evenCount) % mod;
oddCount++;
}
}
return (int) ans;
}
}