Study/자료구조

나머지 합 구하기 - 백준 10986

coldtruthk 2024. 5. 16. 17:33

문제

수 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)

출력

첫째 줄에 연속된 부분 구간의 합이 M으로 나누어 떨어지는 구간의 개수를 출력한다.

 

예제 입력 1

5 3
1 2 3 1 2

예제 출력 1

7

 

#3/1,2/1,2/1,2,3/2,3,1/3,1,2/1,2,3,1,2 => 7게

 

<나머지 합 문제 풀이의 핵심 아이디어>

#   1.(A+B) % C = ((A % C) +(B% c))
#   2. 구간 합 배열을 이용한 식 S[i] - S[j]는 원본 리스트의 j+1부터 i까지의 구간 합이다.
#   => 이 두가지의 이론을 합쳐서 문제를 풀어 볼 수 있다.

 

<Before Coding>

손으로 풀어보기

<슈도 코드 작성하기>

n 입력 받기(수열의 개수)
m 입력 받기(나누어 떨어져야 하는 수)
A 입력 받기(원본 수열 저장 리스트)
S 선언하기(합 배열)
C 선언하기(같은 나머지의 인덱스를 카운트 하는 리스트)
answer 선언하기(정답변수)
for i -> 1~ n-1:
      S[i] = S[i-1] + A[i] //합배열 저장
for i -> 0 ~ n-1:
      remainder = S[i] % M //합 배열을 M으로 나눈 나머지 값
      if(remainder == 0) 정답을 1 증가
      C[remainder]의 값을 1 증가
for i-> 0 ~ m-1:
  C[i](i가 나머지인 인덱스의 개수)에서 2가지를 뽑는 경우의 수를 정답에 더하기
결괏값(answer 출력)

 

<코드 작성하기>

import sys
input = sys.stdin.readline
n,m= map(int, input().split())
A = list(map(int, input().split()))
S = [0] * n
C = [0] * m
answer =0

S[0]=A[0]
for i in range (1,n):
    S[i]= S[i-1]+A[i]

for i in range(n):
    remainder = S[i]%m
    if remainder ==0:
        answer +=1
    C[remainder] +=1

for i in range(m):
    if C[i]>1:
        answer +=( C[i]*(C[i]-1)) //2 

print(answer)