import sys
import bisect
def time_str_num(times):
return times[:4]+times[5:7]+times[8:10]+times[11:13]+times[14:16]+times[17:19]
input = sys.stdin.readline
N,Q = map(int,input().split())
lev_list = [[] for _ in range(7)]
for _ in range(N):
times,lev = input().split('#')
times = time_str_num(times)
lev_list[int(lev)].append(times)
result = []
for _ in range(Q):
s_time,e_time,lev = input().split('#')
s_time = time_str_num(s_time)
e_time = time_str_num(e_time)
lev = int(lev)
cnt = 0
for cu_lev in range(lev,7):
s_ind = bisect.bisect_left(lev_list[cu_lev],s_time)
e_ind = bisect.bisect_right(lev_list[cu_lev],e_time)
cnt += (e_ind-s_ind)
result.append(cnt)
for i in range(Q):
sys.stdout.write(str(result[i])+'\n')
대회때 시간초과가 났던 문제다.
이 문제는 https://programmers.co.kr/learn/courses/30/lessons/17676 와 https://programmers.co.kr/learn/courses/30/lessons/72414 에서 비슷한 느낌을 받았던 문제이다.
이 2문제 전부 긴 시간대를 주고 문제에 주어진 것에서 최대값을 찾던가, 시간내에 있는 기록등을 찾는 방식이다.
이 문제 또한, 각종 로그들이 특정시간대에 나고, 시작시간과 종료시간 내에 발생한 로그의 개수를 세는 것이다.
푸는 방식은 다음과 같다. 레벨별로 시간을 나눠서 저장을 하는것이다.
어차피 들어오는 로그는 순서대로 들어오기 때문에, 작은순서대로 정렬되어서 들어가진다.
또한 년월일시분초를 다 합쳐서 14글자의 숫자로 저장해주면, 문자열로 저장해놔도, 대소구분이 되기 때문에 괜찮다.
그러면 문제에 주어진 로그들을 맞는 레벨에 하나씩 추가를 해준다.
그리고 로그가 들어오면 시작시간과 끝시간을 분리를 해놓는다.
그리고 이분탐색을 통해, 시작시간은 이 시간이 들어가야할 최소 위치,
끝시간은 이 시간이 들어갈수 있는 최대 위치를 구해준다.
인덱스 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
값 | 1 | 2 | 3 | 3 | 3 | 4 | 4 | 4 | 5 |
위와 같은 리스트가 있다고 하고,
시작시간은 3이고, 끝시간은 4라 한다면,
시작시간은 2번인덱스을 가리켜야하고, 끝시간은 8번 인덱스를 가리켜야한다.
그러면, 8-2 = 6개가 나오는 걸 볼 수 있다.
이걸 나는 python에서 이분탐색을 위한 라이브러리인 bisect를 이용해서 bisect_left와 bisect_right를 통해 구현을 했다.
그리고 주어진 로그의 레벨이상을 전부 구하는 것이므로, 주어진 레벨에서부터 최대레벨인 6까지 전체 탐색을 해주었다.
import sys
import bisect
def time_str_num(times):
return times[:4]+times[5:7]+times[8:10]+times[11:13]+times[14:16]+times[17:19]
input = sys.stdin.readline
N,Q = map(int,input().split())
lev_list = [[] for _ in range(7)]
for _ in range(N):
times,lev = input().split('#')
times = time_str_num(times)
for i in range(1,int(lev)+1):
lev_list[i].append(times)
for _ in range(Q):
s_time,e_time,lev = input().split('#')
s_time = time_str_num(s_time)
e_time = time_str_num(e_time)
lev = int(lev)
cnt = 0
s_ind = bisect.bisect_left(lev_list[lev],s_time)
e_ind = bisect.bisect_right(lev_list[lev],e_time)
cnt += (e_ind-s_ind)
sys.stdout.write(str(cnt)+'\n')
이 풀이는 위의 풀이와 똑같지만, 반복작업을 없애준 것이다.
처음 로그가 들어올때부터, 1레벨부터 현재 레벨까지 전부 넣어주는것이다.
어차피 레벨 이상의 쿼리를 전부 조회하는 것이므로, 로그로 들어온 레벨 이하에 전부 저장을 해주고,
이분 탐색을 한번만 해서 출력할 수 있도록 해준 것이다.
대회시간에는 못 풀었지만 류호석님의 조언을 듣고 바로 풀 수 있었던 문제였다.
이전에 풀었던 문제들을 조금만 응용하면 풀수 있는 문제였지만, 제대로 응용하지 못한 패착인것 같다.
'알고리즘 > 백준' 카테고리의 다른 글
[BOJ/백준] 21776 가희의 읽기 쓰기 놀이 (0) | 2021.06.05 |
---|---|
[BOJ/백준] 21775 가희와 자원 놀이 (0) | 2021.06.02 |
[BOJ/백준] 21773 가희와 프로세스 1 (0) | 2021.05.27 |
[BOJ/백준] 21772 가희와 고구마 먹방 (0) | 2021.05.27 |
[BOJ/백준] 21771 가희야 거기서 자는거 아니야 (0) | 2021.05.27 |