문제
https://www.acmicpc.net/problem/10986
10986번: 나머지 합
수 N개 A1, A2, ..., AN이 주어진다. 이때, 연속된 부분 구간의 합이 M으로 나누어 떨어지는 구간의 개수를 구하는 프로그램을 작성하시오. 즉, Ai + ... + Aj (i ≤ j) 의 합이 M으로 나누어 떨어지는 (i, j)
www.acmicpc.net
이해
- 구간의 합을 구해야하는 문제이므로 누적 합 알고리즘을 활용한다.
- N의 범위가 100,000이므로 O(N)만큼 활용할 수 있고, 탐색을 통해 선택해야 하므로 이분 탐색이나 투포인터를 활용해야한다.
- 배열 값의 범위가 1,000,000,000이므로 이를 매번 다루면 연산 시간으로 인해 시간 초과가 염려되니, M으로 나눈 나머지 값을 가지고 활용한다. (최대 1,000,000,000 → 최대 1,000,000)
- 두 인덱스를 두고, 각 인덱스의 나머지값이 같으면 두 값의 차이는 M의 배수가 된다.
- 예를들어 각 인덱스 값이 [5, 9]라고 했을 때 M = 4이면, 나머지는 [1, 1]이고, 두 값의 차는 4로 M으로 나누어 떨어진다.
- 따라서 나머지 값이 같은 인덱스 개수를 세고, 그중 2개를 고르는 경우의 수이다.
- 단, 나머지가 0인 경우, 첫번째부터의 누적합이므로 더해줘야 함
구현
- 누적 합 구하기
for i in range(1, N): arr[i] = arr[i] + arr[i-1]
- 나머지의 개수 구하기
from collections import defaultdict # define remain = defaultdict(int) # 나머지의 개수 세기 remain[arr[0]%M] += 1 for i in range(1, N): remain[arr[i] % M] += 1
- 2개를 뽑는 경우의 수 계산
- n개중 k개를 고르는 조합 식: nCk = n! / {(n-k)!k!}
- n개중 2개를 고르는 조합 식: nC2 = n(n-1) / 2
- 나머지가 0인 요소들은 기본적으로 0번째부터의 누적합이므로 더해줘야함
# 나머지 개수 중 2개 뽑아서 더하기(조합) ans = remain[0] for cnt in remain.values(): ans += cnt * (cnt-1) // 2
코드
# 10986 나머지 합
import sys
from collections import defaultdict
input = sys.stdin.readline
def main():
# 입력
N, M = map(int, input().split())
arr = list(map(int, input().split()))
# define
remain = defaultdict(int)
# 나머지의 개수 세기
remain[arr[0]%M] += 1
for i in range(1, N):
arr[i] = arr[i] + arr[i-1]
remain[arr[i] % M] += 1
# 나머지 개수 중 2개 뽑아서 더하기(조합)
ans = remain[0]
for cnt in remain.values():
ans += cnt * (cnt-1) // 2
# 출력
print(ans)
if __name__ =="__main__":
main()
참조
2024.04.02 - [Algorithm/개념] - [알고리즘] 누적합(Prefix Sum)
[알고리즘] 누적합(Prefix Sum)
개념 특정 배열이 있을 때, 구간의 합을 말한다. 예를 들어, 다음과 같은 배열이 있을 때 3번째부터 5번째까지의 누적합은 12이다. 구현 일반적으로 누적합을 구함에 있어, i번째부터 j번째까지의
l1m3kun.tistory.com
느낀점
- 단순 누적합이라고 생각할 수 있지만, 조금 더 생각하면 수학을 더한 응용이여서 한 번 더 생각해야 풀 수 있는 문제였다.
- n개 중 2개를 고를 때 n*(n-1)/2 로 간단하게 구할 수 있어 나중에도 자주 사용할 수 있을 것 같았다.
- 두 용액과 유사한 문제였지만, 투 포인터를 사용하지 않고도 풀 수 있어 좋은 경험을 쌓았다.
반응형
'Algorithm > BaekJoon Review' 카테고리의 다른 글
11286. 절댓값 힙 (0) | 2024.03.12 |
---|---|
13549. 숨바꼭질 3 (2) | 2024.01.31 |
12851. 숨바꼭질 2 (2) | 2024.01.31 |
1697. 숨바꼭질 (2) | 2024.01.29 |
9935. 문자열 폭발 (0) | 2024.01.21 |