첫 줄에 전봇대의 개수 N(1 ≤ N ≤ 100,000)이 주어지고, 이어서 N보다 작거나 같은 자연수가 N개 주어진다. i번째 줄에 입력되는 자연수는 길 왼쪽에 i번째 전봇대와 연결된 길 오른편의 전봇대가 몇 번 전봇대인지를 나타낸다.
출력
전선이 꼬이지 않으려면 최소 몇 개의 전선을 잘라내야 하는 지를 첫째 줄에 출력한다.
입력 예시
4
2 3 4 1
출력 예시
1
풀이
우선은 전기줄이 안 꼬이는 조건을 생각해 보자. 전기줄이 일렬로 배치되어 있는 경우가 될 것이다. 조금 더 구체적으로 생각해 보면, 왼편의 이전 전기줄과 오른편의 이전 전기줄보다 왼쪽, 오른쪽 모두 더 뒤에 존재해야 한다.
수학적으로 생각해 보면, 왼편의 전봇대가 n이라고 했을 때 오른쪽 전봇대를 매핑하는 함수를 f(n)이라고 두자. 그렇다면 꼬이지 않을 때, 임의의 n, m (n < m) 에 대하여 f(n) < f(m)이 만족되어야 한다. 즉 증가함수의 형태를 띄어야 한다.
여기까지 왔다면 다음은 더 쉬워진다. 전기줄이 안 꼬이는 조건으로 증가함수의 형태를 띔을 알았고, 우리는 잘라내는 전선을 최소로 하고 싶다. 즉 잘라내지 않는 전선을 최대로 하고 싶다는 의미이다. 이는 최장 증가 부분 수열을 찾는 문제에 해당한다. N이 최대 100000이므로, 이분 탐색을 이용하여 O(NlogN)시간 내에 처리해 볼 수 있을 것이다.
N = int(input())
nums = list(map(int, input().split()))
n_list = list()
def lower_bound(val) :
start, end = 0, len(n_list)-1
while start < end :
mid = (start + end) // 2
if n_list[mid] < val :
start = mid+1
else :
end = mid
return end
for num in nums :
if not n_list or n_list[-1] < num :
n_list.append(num)
else :
idx = lower_bound(num)
n_list[idx] = num
print(N-len(n_list))