문제 링크
- http://icpc.me/21162
사용 알고리즘
- 해싱
시간복잡도
- $O(N \log^2 N)$
풀이
오랜만에 BOJ에 문제를 올렸습니다.
두 수열을 잘 쪼갠 뒤 각각 뒤집어서 붙이는 것은 무엇을 의미할까요? 앞부분과 뒷부분을 각각 X개와 N-X개로 쪼개면 수열은 $A[X], A[X-1], A[X-2], \cdots , A[1], A[N], A[N-1], \cdots , A[X+1]$이 됩니다.
입력으로 들어온 수열을 뒤집어서 생각하면, 수열을 $[1, N)$번 Cyclic Shift한 수열을 만들게 됩니다.
K-th Lexicographically Cyclic Shift를 찾는 문제가 되었습니다. 문자열(수열)의 Cyclic Shift는 문자열을 2배 늘려주면 처리하기 쉬워집니다. 그러므로 우리는 $A[2..N+1], A[3..N+2], \cdots , A[N..2N-1]$ 중 사전순 $K$번째 문자열(수열)을 찾으면 됩니다.
부분 문자열의 사전순 비교를 $T(N)$ 시간에 할 수 있다면, 만들 수 있는 모든 문자열을 나열한 뒤 $O(T(N) \cdot N \log N)$에 정렬하고 $K$번째 문자열을 출력하는 것으로 문제를 해결할 수 있습니다. 이 글에서는 문자열의 사전순 비교를 $O(\log N)$에 하는 방법을 소개합니다.
두 문자열이 완전히 같은지 확인하는 것은 해싱을 이용해 $O(1)$에 할 수 있다는 것이 잘 알려져 있습니다.
ㅇ러떤 두 문자열 $A, B$가 있을 때, $A$가 $B$보다 사전순으로 앞선다는 것은, 어떤 자연수 $X$가 있어서 $A[..X-1]$과 $B[..X-1]$이 서로 같고 $A[X]$와 $B[X]$가 다르며(처음으로 다른 위치가 $X$이며), $A[X] < B[X]$라는 것을 의미합니다. 그러므로 두 문자열이 처음으로 달라지는 위치를 파라메트릭 서치를 이용해 $O(\log N)$만에 찾고, 그 지점의 문자를 비교하면 됩니다.
두 문자열을 $O(\log N)$만에 비교할 수 있으므로 $N$개의 부분 문자열을 $O(N \log^2 N)$에 정렬할 수 있습니다.
아래 코드는 단일 해시를 사용한 코드이며, 해싱을 2-3중으로 사용하고 싶다면 다음과 같이 cmp 함수를 수정하면 됩니다.
1 |
|
전체 코드
1 |
|