| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- Meet in the middle
- BFS
- concurreny
- 알고리즘
- 이분 탐색
- SCC
- springdoc
- Linux
- kruskal
- BindingAdapter
- disjoint set
- MST
- union-find
- 그래프
- 구현
- 페르마 소정리
- 백트래킹
- miller-rabin
- 위상 정렬
- 누적 합
- 위상정렬
- tarjan
- MySQL
- kapt
- 투 포인터
- DP
- Java
- DFS
- 분리 집합
- spring boot
- Today
- Total
기맹기 개발 블로그
[BOJ 10986] 나머지 합 (Java) 본문
BOJ 10986 나머지 합
난이도 : 골드 3
https://www.acmicpc.net/problem/10986
10986번: 나머지 합
수 N개 A1, A2, ..., AN이 주어진다. 이때, 연속된 부분 구간의 합이 M으로 나누어 떨어지는 구간의 개수를 구하는 프로그램을 작성하시오. 즉, Ai + ... + Aj (i ≤ j) 의 합이 M으로 나누어 떨어지는 (i, j)
www.acmicpc.net
전략
수열의 길이 N은 최대 10^6이므로 모든 부분 구간을 탐색하는 O(N^2)으로는 풀 수 없다.
누적 합을 이용하면 두 지점 사이의 부분 배열의 합을 구할 수 있다.
나는 누적합 % M이 반복되었을 때 해당 구간의 합 % M은 0이 되는 것을 주목했다.
문제의 예제를 예로 들어보자.
N = 5, M = 3
수열 : 1 2 3 1 2
누적합 % M : 1 0 0 1 0
값이 0이 되는 지점은 당연히 포함해야되며
0이 아닌 지점은 반복되는 곳을 잘 봐야한다.
1이 처음 등장할 때는 당연히 % M이 0이 될 수 없지만,
두번째 등장할 때는 두 지점 사이의 부분합의 % M은 0이 된다.
만약 여러번 등장한다면 어떻게 될까?
index 0, 3, 5에서 % M이 1이 되었다면
0 ~ 3 구간, 0 ~ 5구간, 3 ~ 5구간이 포함되어야 한다.
T번째로 % M이 1이 된다면 + (T - 1)만큼 해줘야 된다.
따라서 M 크기의 배열을 이용해 % M이 각 몇번 등장하는지 기록해놓으면서 진행하면 O(N)에 계산이 가능하다.
M은 최대 10^3이므로 공간도 충분하다.
주의할 점은 0은 한번만 나와도 개수를 세어야 하고, 나머지는 두번째부터 개수를 세어야한다.
따라서 나는 두 경우를 분리해서 전위/후위 연산으로 구현했다.
시행착오
결과를 int로 저장했었는데, N^2만큼 커질 수 있으므로 long으로 변경했다.
코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N, M;
String[] line = br.readLine().split(" ");
N = Integer.parseInt(line[0]);
M = Integer.parseInt(line[1]);
StringTokenizer st = new StringTokenizer(br.readLine());
int[] cnt = new int[M];
long sum = 0;
long ans = 0;
for (int i=0; i<N; i++) {
sum += Integer.parseInt(st.nextToken());
int idx = (int) (sum % M);
if (idx == 0)
ans += ++cnt[idx];
else
ans += cnt[idx]++;
}
System.out.println(ans);
}
}
누적 합 외에는 다른 정보가 필요 없어서 수열은 따로 저장하지 않고 입력 받으면서 진행했다.
사실 모듈러의 성질 때문에 sum을 int로 잡고 계속 mod 연산을 해줘도 상관은 없다.
하지만 최대 10^9인 수를 10^3 번 더해도 long으로 표현가능하므로 그냥 간단하게 표현했다.
'PS' 카테고리의 다른 글
| [BOJ 10775] 공항 (Java) (0) | 2022.08.21 |
|---|---|
| [BOJ 9527] 1의 개수 (Java) (0) | 2022.08.20 |
| [BOJ 2143] 두 배열의 합 (Java) (0) | 2022.08.18 |
| [BOJ 1799] 비숍 (Java) (0) | 2022.08.17 |
| [BOJ 1644] 소수의 연속합 (Java) (0) | 2022.08.17 |