백준 10986 | 나머지 합[파이썬 python]

2023. 10. 24. 22:11·Algorithm/백준
 

10986번: 나머지 합

수 N개 A1, A2, ..., AN이 주어진다. 이때, 연속된 부분 구간의 합이 M으로 나누어 떨어지는 구간의 개수를 구하는 프로그램을 작성하시오. 즉, Ai + ... + Aj (i ≤ j) 의 합이 M으로 나누어 떨어지는 (i, j)

www.acmicpc.net

 

코드

n, m = map(int, input().split()) # n개의 수, M으로 나누기
A = list(map(int, input().split())) # n개의 수로 이루어진 원본 배열

S = [] # 합 배열
M = [] # 합 배열 S를 M으로 나눈 나머지

answer = 0 # M으로 나눠지는 (i, j) 쌍의 개수

temp = 0
for i in A:
    temp += i
    S.append(temp) # 누적 합
    
    M.append(temp % m) # 누적 합 % m
    
    # 나누어 떨어지면(i에서 i 구간) answer +1
    if temp % m == 0:
        answer += 1
    
# (i, j) 구간 합이 m으로 나누어 떨어지면
# (S[j]-S[i-1]) % m == 0 이므로 S[j] % m == S[i-1] % m 
# 즉, M[j] == M[i-1]이면 (i, j) 구간 합이 m으로 나누어 떨어진다
# 누적합의 나머지가 같은 인덱스 중에 2개를 뽑는 경우의 수 

# 나머지의 개수 파악(m=3이면 나머지는 0, 1, 2 셋 중 하나)
mod_count = [0] * m
for i in M:
    mod_count[i] += 1
    
for i in mod_count:
    answer += i * (i-1) // 2 # i개 중에 2개를 뽑는 경우의 수(2C1)

print(answer)

코드를 이해하고 나면 쉽게 느껴지지만 누적 합에 대한 개념을 확실히 가지고 있어야 풀 수 있는 문제이다.

 

먼저, 합 배열 S와 S를 m으로 나눈 나머지를 저장하는 배열 M을 만든다.

M을 만들 때 누적 합 S가 m으로 나누어 떨어지면(temp % m == 0) (i, i) 구간에서 조건을 만족하므로 순서쌍의 개수 answer+1을 해준다.

S = [] # 합 배열
M = [] # 합 배열 S를 M으로 나눈 나머지

temp = 0
for i in A:
    temp += i
    S.append(temp) # 누적 합
    
    M.append(temp % m) # 누적 합 % m
    
    # 나누어 떨어지면(i에서 i 구간) answer +1
    if temp % m == 0:
        answer += 1

 

이제 나머지 배열인 M에서 m으로 나누어 떨어지는 (i, j) 구간을 구해야 하는데 이를 식으로 보면 다음과 같다. 

(i, j) 구간 합이 m으로 나누어 떨어지면 (S[j]-S[i-1]) % m == 0 이므로 S[j] % m == S[i-1] % m임을 알 수 있다.

즉, S[j] % m = M[j]와 같으므로 식을 다시 쓰면 M[j] == M[i-1]인 구간 (i, j)를 찾아야 하는 것이다.

따라서 합 배열의 나머지가 같은 인덱스 중에 2개를 뽑는 경우의 수를 세어주면 되는데 이를 위해 m으로 나눴을 때의 나머지가 몇 번씩 등장하는지 파악할 배열 mod_count를 만든다.

 

mode_count의 길이는 m과 같다. 그 이유는 m=3이면 3으로 나눴을 때 나머지는 0, 1, 2 셋 중 하나이므로 가능한 나머지는 m개다.

# 나머지의 개수 파악(m=3이면 나머지는 0, 1, 2 셋 중 하나)
mod_count = [0] * m
for i in M:
    mod_count[i] += 1

 

M에서 나머지의 개수를 파악한 뒤에는 경우의 수를 계산해 주면 된다.

2개를 뽑아야 하므로 $_nC_2 = \frac {n \times (n-1)}{2}$임을 활용해 구할 수 있다.

for i in mod_count:
    answer += i * (i-1) // 2 # i개 중에 2개를 뽑는 경우의 수(iC2)

 

answer를 구하기 위해 배열 M과 mod_count 두 개를 사용했는데, 이 과정을 축소해 다음과 같이 더 간결하게 코드를 작성할 수 있다.

n, m = map(int, input().split()) # n개의 수, M으로 나누기
A = list(map(int, input().split())) # n개의 수로 이루어진 원본 배열

S = [] # 합 배열
mod_count = [0] * m

temp = 0
for i in A:
    temp += i
    S.append(temp) # 누적 합
    mod_count[temp % m] += 1 # 누적 합 % m
    
# m으로 나누어 떨어지는 (i, j) 순서쌍의 개수
answer = mod_count[0] # 나누어 떨어지는 경우 = (i, i)
for i in mod_count:
    answer += i * (i-1) // 2 # i개 중에 2개를 뽑는 경우의 수(iC2)

print(answer)
반응형
저작자표시 (새창열림)
'Algorithm/백준' 카테고리의 다른 글
  • 백준 24511 | queuestack [파이썬 python]
  • 백준 1967, 1167 | DFS/BFS | 트리의 지름 [파이썬 python]
  • 백준 11660 | DP | 구간 합 구하기 [파이썬 python]
  • 백준 1003 | DP | 피보나치 함수 [파이썬 python]
dduniverse
dduniverse
  • dduniverse
    dduniverse
    dduniverse
  • 전체
    오늘
    어제
    • 분류 전체보기 (242)
      • Algorithm (123)
        • 알고리즘 이론 (8)
        • 백준 (19)
        • 프로그래머스 (83)
        • 구름 알고리즘 먼데이 챌린지 (13)
      • 빅데이터분석기사 (10)
        • 통계 (4)
        • 실기 (6)
      • KT에이블스쿨 (26)
      • FrontEnd (11)
        • React (5)
        • 기타 (6)
      • BackEnd (18)
        • Django (15)
        • Spring (3)
      • DS & ML (11)
        • Machine Learning (9)
        • Kaggle (2)
      • TIL (43)
        • python (22)
        • javascript (3)
        • 오류해결 (10)
        • 기타 (7)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • 관리
    • 글쓰기
  • 링크

  • 인기 글

  • hELLO· Designed By정상우.v4.10.0
dduniverse
백준 10986 | 나머지 합[파이썬 python]
상단으로

티스토리툴바