링크 : https://www.acmicpc.net/problem/2143
2143번: 두 배열의 합
첫째 줄에 T(-1,000,000,000 ≤ T ≤ 1,000,000,000)가 주어진다. 다음 줄에는 n(1 ≤ n ≤ 1,000)이 주어지고, 그 다음 줄에 n개의 정수로 A[1], …, A[n]이 주어진다. 다음 줄에는 m(1 ≤ m ≤ 1,000)이 주어지고, 그
www.acmicpc.net
코드
from collections import defaultdict
T = int(input())
n = int(input())
A = list(map(int, input().split()))
m = int(input())
B = list(map(int, input().split()))
sum_A, sum_B = [0], [0]
for i in range(n):
sum_A.append(sum_A[i] + A[i])
for i in range(m):
sum_B.append(sum_B[i] + B[i])
dic = defaultdict(int)
for i in range(n + 1):
for j in range(i + 1, n + 1):
dic[sum_A[j] - sum_A[i]] += 1
result = 0
for i in range(m + 1):
for j in range(i + 1, m + 1):
result += dic[T - (sum_B[j] - sum_B[i])]
print(result)
풀이
기본적인 부분합 문제였다면 부분 합이 T인 경우의 수를 구하는 것이었겠지만 이 문제는 좀 더 어렵게 꼬아서 두 배열의 부분 합의 합이 T인 경우의 수를 구해야 한다.
여기서 경우의 갯수만 출력하면 되므로 모든 부분합의 원소들을 저장할 필요는 없다.
< 모든 부분합 탐색 - 시간초과 >
처음에는 A,B 두 집합의 모든 부분합을 검사하면서 T이하인 부분합의 합을 배열에 모두 저장하고 그렇게 만들어진 두 배열의 탐색하면서 합이 T이면 정답을 1씩 올려주었다.
이렇게 하면 모든 경우의 수를 다 탐색하고 저장한 것이므로 당연하게도 시간초과가 발생했다.
< 딕셔너리 사용 - 통과 >
먼저 A와 B의 누적합 배열을 만든다. - sum_A, sum_B
A의 모든 부분합을 탐색하면서 딕셔너리에 부분합을 인덱스로 하여 해당 값이 나올 때마다 1씩 더해준다.
이 때, 딕셔너리를 이용하는 이유는 딕셔너리의 값에 접근할 때는 O(1) 시간복잡도가 필요하고 defaultdict 라이브러리를 사용하면 딕셔너리 키값이 없어도 자동으로 추가해주기 때문이다. - dic = defaultdict(int)
B의 누적합을 모두 탐색하며 위에서 만들어 놓은 부분합과 더해서 T가 되는 경우를 result에 더해준다.
이 때, T - B의 부분합 = A의 부분합이므로 dic[T-B의 부분합]의 값을 더해주면 된다.
defaultdict 라이브러리를 사용했기 때문에 만약 A의 부분합이 없다면, 즉 dic의 키 값이 없다면 0이 더해진다.
'알고리즘 > BAEKJOON (Python)' 카테고리의 다른 글
[ 백준 ][ 골드2 ] 2263번 - 트리의 순회 ( 파이썬 Python3 ) (0) | 2023.03.12 |
---|---|
[ 백준 ][ 골드2 ] 1368번 - 물대기 ( 파이썬 PYTHON3 ) (0) | 2023.03.11 |
[ 백준 ][ 골드1 ] 3665번 - 최종 순위 ( 파이썬 Python ) (0) | 2023.03.07 |
[ 백준 ][ 골드5 ] 9251번 - LCS ( 파이썬 Python ) (0) | 2023.03.06 |
[ 백준 ][ 골드2 ] 1826번 - 연료 채우기 ( 파이썬 Python ) (0) | 2023.03.05 |