https://www.acmicpc.net/problem/3151

 

3151번: 합이 0

Elly는 예상치 못하게 프로그래밍 대회를 준비하는 학생들을 가르칠 위기에 처했다. 대회는 정확히 3명으로 구성된 팀만 참가가 가능하다. 그러나 그녀가 가르칠 학생들에게는 큰 문제가 있었다.

www.acmicpc.net


  • 중복되지 않게 3명을 뽑아서 0 을 맞춰야 하는 문제이므로, 2명의 값이 정해지면 3번째 값은 자동으로 정해진다.
  • 2명의 값을 정하기 위해 N * N 번 탐색을 하게 되면, 3번째 값을 찾기 위해선 이분탐색이더라도 logN 번이 필요하다.
  • 그러나 투 포인터를 활용하면 N * N * logN 보다 더 빠른, N * N 으로 끝낼 수 있다.
  • 첫번째 사람의 값을 고정해놓고(N), 나머지 두 학생의 값을 양쪽에 포인터를 두고 0 에 수렴하도록 옮겨주면 N 번이 걸린다.
  • 이 때 값은 같더라도 다른 사람일 경우에 대해서는 세심한 예외처리가 필요하다.

N = int(input())
st = sorted(list(map(int, input().split())))
answer = 0

# 첫번째 수를 고정적으로 뽑아놓고 나머지 두 수 결정
for idx in range(N-2):
    # 두 수를 결정하기 위해 투 포인터를 써서 앞뒤로 범위를 줄여 O(N) 에 탐색
    target, l, r = -st[idx], idx + 1, N-1
    while l < r:
        cur = st[l] + st[r]
        # 만약 두 수가 우리가 원하던 값이라면
        if cur == target:
            curl, curr = st[l], st[r]
            # 그리고 두 수가 같은 수라면 그 수들로부터 2개를 뽑는 경우의 수만큼 팀 구성 가능(정렬되어있기 때문)
            if curl == curr:
                # 조합 계산식
                answer += (r-l+1)*(r-l)//2
                break
            # 두 수가 다른 수라면, 왼쪽포인터가 가리키는 수의 갯수 * 오른쪽포인터가 가리키는 수의 갯수
            else:
                dl, dr = 0, 0
                # 왼쪽 수의 개수를 구함
                while st[l] == curl:
                    dl += 1
                    l += 1
                # 오른쪽 수의 개수
                while st[r] == curr:
                    dr += 1
                    r -= 1
                answer += dl * dr
        elif cur < target:
            l += 1
        elif cur > target:
            r -= 1
print(answer)

'PS > BOJ' 카테고리의 다른 글

[백준] 3980 : 선발 명단  (0) 2021.07.29
[백준] 20208 : 진우의 민트초코우유  (0) 2021.07.27
[백준] 2342 : Dance Dance Revolution  (0) 2021.07.25
[백준] 9020 : 골드바흐의 추측  (0) 2021.07.24
[백준] 10421 : 수식 완성하기  (0) 2021.07.23

+ Recent posts