D - Intersecting Intervals (atcoder.jp)
D - Intersecting Intervals
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.
atcoder.jp
50만개의 구간 [l,r]이 주어질때, 이들 중 서로 겹치는 구간 쌍의 개수가 몇개인지 구하는 문제
모든 구간 쌍에 대해 서로 겹치는지 조사할려면 O(N2)인데, 당연히 N이 최대 50만이므로 시간제한에 맞지 않는다
전체 구간 쌍의 개수는 n개중 2개를 선택하는 경우의 수이므로, nC2 = n(n-1)/2
만약 서로 겹치치 않는 구간 쌍의 개수를 구할 수 있다면, nC2에서 이 개수를 빼면 서로 겹치는 구간 쌍의 개수를 구할 수 있다
어떤 구간 i가 li,ri이면, 이 구간 i와 공통 부분이 없는 구간은 lj,rj에 대하여, rj<li를 만족해야한다.
그러므로 모든 i = 1,2,3,..,n에 대하여 rj<li를 만족하는 j의 개수를 구해 더하면 된다.
[l,r]에 대하여 l을 모아둔 L과 r을 모아둔 R을 구하고 이들을 오름차순으로 정렬한다.
L1 < L2 < ... < LN
R1 < R2 < ... < RN
먼저 i = 0일때 j = 0부터 시작해서 rj<li를 만족하면 j를 1씩 증가시킨다.
처음으로 rj>li라면, 0~j-1까지가 rj<li를 만족하므로 총 j개를 빼면 된다.
다음 i = 1로 가는데, 다시 j = 0부터 시작해서 rj<li를 만족하면 j를 1씩 증가시키는 것을 반복해야할까?
이러면 여전히 O(N2)이다.
하지만 L,R이 오름차순으로 정렬되어 있기 때문에, rj−1<li<li+1를 알 수 있다.
그러므로 이전에 i = 0일때 구해둔 j = 0,1,2,..,j-1까지는 여전히 li+1보다 작다.
이 구간들은 여전히 li+1,ri+1과 겹치지 않기 때문에 카운팅을 가지고 가줘야한다.
그래서 j = 0으로 바꾸지 않고 이 j부터 시작해서 rj>li+1이 될 때 까지 j를 1씩 증가시키자.
rj>li+1이면 다시 answer에 j를 빼준다.
이를 반복하면 O(N)이므로 전체는 정렬에 의한 시간복잡도 O(NlogN)에 해결할 수 있다
from sys import stdin
n = int(stdin.readline())
L = []
R = []
for _ in range(n):
l,r = map(int,stdin.readline().split())
L.append(l)
R.append(r)
L.sort()
R.sort()
answer = n*(n-1)//2
j = 0
for i in range(n):
while R[j] < L[i]:
j += 1
answer -= j
print(answer)
'알고리즘 > 투 포인터 알고리즘' 카테고리의 다른 글
절댓값을 풀어내는 필수 테크닉 - 모든 i,j에 대해 (i-j)|ai-bj|의 합을 빠르게 구하는 방법 (0) | 2024.10.24 |
---|---|
배열에서 두 수의 합이 s가 되는 경우의 수(서로 다른 방향으로 움직이는 투 포인터) (0) | 2024.09.02 |
투 포인터로 원소를 삭제하면서 가장 긴 수열을 찾을 수 있을까? (0) | 2023.06.08 |
투 포인터 올바르게 생각하기 기본문제로 연습2 (0) | 2023.04.12 |
투 포인터 기억해야할 점 - 끝 포인터를 처음으로 옮기지 않기 (0) | 2023.04.11 |