문제
백준 10986번 나머지 합 / 골드3
수 N개 A1, A2, ..., AN이 주어진다. 이때, 연속된 부분 구간의 합이 M으로 나누어 떨어지는 구간의 개수를 구하는 프로그램을 작성하시오.
즉, Ai + ... + Aj (i ≤ j) 의 합이 M으로 나누어 떨어지는 (i, j) 쌍의 개수를 구해야 한다.
입력
첫째 줄에 N과 M이 주어진다. (1 ≤ N ≤ 106, 2 ≤ M ≤ 103)
둘째 줄에 N개의 수 A1, A2, ..., AN이 주어진다. (0 ≤ Ai ≤ 109)
풀이
누적 합 문제이다. 하지만 단순히 모든 구간의 누적 합을 구하게 되면 입력 N이 106이므로 시간복잡도는 O(n2)로 시간 초과가 발생한다.
그래서 M으로 나누었을 때, 나머지가 같은 수를 카운트 해주는 배열 remainders
를 만들었다. remainders
배열의 index
가 나머지이다. 이 나머지가 같은 수 2개를 빼면 M의 배수가 나오게 된다. 그렇기에 각 배열에 저장된 수를 조합 계산하면 remainders[i] = n
일 때, n(n-1)/2
이라는 계산식이 나온다.
누적 합을 구하기 위해서는 이전 누적 합을 저장하는 prevSum
과 현재 누적 합을 저장하는 sum
, 누적 합이 M으로 나누어떨어지는 수를 저장하는 remainderZero
를 사용했다. 이 누적 합들의 수 2개를 빼면 마찬가지로 M의 배수가 나오게 된다. 그렇기에 remainderZero = n
일 때, n+(n(n-1)/2) = n(n+1)/2
이라는 식이 나오게 된다.
코드
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
int M = Integer.parseInt(st.nextToken());
long sum = 0;
long prevSum = 0;
long remainderZero = 0;
long[] remainders = new long[M];
st = new StringTokenizer(br.readLine());
for (int i = 1; i <= N; i++) {
sum = prevSum + Long.parseLong(st.nextToken());
prevSum = sum;
if (sum % M == 0) {
remainderZero++;
} else {
remainders[(int) (sum % M)]++;
}
}
long answer = (remainderZero * (remainderZero + 1) / 2);
for (int i = 0; i < M; i++) {
answer += (remainders[i] * (remainders[i] - 1) / 2);
}
System.out.println(answer);
}
}
'Algorithm > Baekjoon' 카테고리의 다른 글
백준 1517번 버블 소트 (Java) (0) | 2024.09.16 |
---|---|
백준 1377번 버블 소트 (Java) (2) | 2024.09.07 |
백준 17298번 오큰수 (Java) (1) | 2024.09.06 |
백준 11003번 최솟값 찾기 (Java) (0) | 2024.09.03 |
백준 1253번 좋다 (Java) (4) | 2024.09.02 |