접근 방법
누적합+이분탐색 카테고리여서 이분 탐색을 어떻게 사용할지 고민했습니다.
1. 전처리
배열 1개의 경우, 누적합을 구하기 위해 A[0] ~ A[n] 까지 배열을 순회하며 누적합을 넣어주지만 해당 문제를 이렇게 접근해버리면 안된다는 것은 알고 계실겁니다.
# 일반적인 배열 1개의 누적합
arr = [0,1,2,3,4,5,6,7,8,9]
for i in range(1,len(arr)):
arr[i] = arr[i-1]+arr[i]
# result : [0,1,3,6,10,15,21,28,36,45]
2개의 배열이기 때문에 이런 의문이 생길 수 있습니다.
"각 배열의 비교 범위를 어떻게 선택할 것인가?"
B 배열의 탐색 index가 하나 증가하게 되면 A 배열의 index는 처음으로 돌아가 다시 탐색을 해야 하기 때문인데요,
이 것을 전처리 과정을 통해 해결할 수 있습니다.
N = int(input())
Aarr = list(map(int,input().split()))
M = int(input())
Barr = list(map(int,input().split()))
Asum = []
Bsum = []
for i in range(N): #O(A*(A-1)/2) = O(N^2)
s = Aarr[i]
Asum.append(s)
for j in range(i+1,N):
s+=Aarr[j]
Asum.append(s)
for i in range(M): #O(B*(B-1)/2) = O(M^2)
s = Barr[i]
Bsum.append(s)
for j in range(i+1,M):
s+=Barr[j]
Bsum.append(s)
시간 복잡도 : O(N2)
각 index에 대한 누적합을 미리 계산해주는 방식입니다. 모든 누적합이 미리 만들어져 있으니 하나의 Sum array를 기준으로 T 값을 맞추는 게 간편해졌죠
2. 이분 탐색
결국 우리는 T = Asum[i] + Bsum[j] 를 만족시키는 부분 배열을 찾아야 합니다.
다르게 생각하면 T - Asum[i] = Bsum[j]이 되는 것이죠.
이제, Bsum Array를 보고 이런 궁금증이 생깁니다.
Asum+Bsum=T에 해당되는 개수를 어떻게 구할 것인가?
여기서 사용되는 것이 이분 탐색입니다.
이분 탐색에 left와 right 또는 upper_bound, lower_bound를 들어보셨을 겁니다.
Python에서는 lower_bound가 bisect_left로, upper_bound가 bisect_right로 사용되니 표현을 bisect를 사용하겠습니다.
간단히 이 원리에 대해 설명하자면, 정렬된 [1,2,2,2,3]라는 Array에서
bisect_left(2)를 했다면 index 1을 반환하고
bisect_right(2)를 했다면 index 4를 반환하게 됩니다.
여기서 2의 개수는 right - left = 3과 동일합니다.
만약 조건문을 통해 하나씩 카운트했다면 O(N)만큼 소요되므로 O(logN)인 이분 탐색을 이용하는 거죠.
answer = 0
for i in range(len(Asum)):
l = bisect.bisect_left(Bsum,T-Asum[i])
r = bisect.bisect_right(Bsum,T-Asum[i])
answer+=r-l
이 과정을 정렬된 Asum 개수만큼 연산하여 answer에 모든 값을 더해주게 됩니다.
Python 코드
import bisect
T = int(input())
N = int(input())
Aarr = list(map(int,input().split()))
M = int(input())
Barr = list(map(int,input().split()))
Asum = []
Bsum = []
for i in range(N): #O(A*(A-1)/2)
s = Aarr[i]
Asum.append(s)
for j in range(i+1,N):
s+=Aarr[j]
Asum.append(s)
for i in range(M): #O(B*(B-1)/2)
s = Barr[i]
Bsum.append(s)
for j in range(i+1,M):
s+=Barr[j]
Bsum.append(s)
Asum.sort()
Bsum.sort()
answer = 0
for i in range(len(Asum)):
l = bisect.bisect_left(Bsum,T-Asum[i])
r = bisect.bisect_right(Bsum,T-Asum[i])
answer+=r-l
print(answer)
'OnlineJudge' 카테고리의 다른 글
[백준] 17825 주사위윷놀이 python 시간단축 풀이 (0) | 2021.10.04 |
---|---|
[백준] 15684 사다리 조작 풀이 Python, Java (0) | 2021.09.22 |
[백준] 2573 빙산 풀이 Python (0) | 2021.09.14 |
백준 1016 제곱ㄴㄴ수 풀이 Python (2) | 2021.06.24 |
[Codility] Lesson4 MaxCounters 풀이 Python (0) | 2021.06.22 |
인프런 지식공유자로 활동하고 있으며 MSA 전환이 취미입니다. 개발과 관련된 다양한 정보를 몰입감있게 전달합니다.