https://www.acmicpc.net/problem/12014
문제 탐색하기
문제에서는 아래와 같이 설명이 장황하게 되어있지만 결국 원하는 건 가장 긴 증가하는 수열이다.
주식을 살 때마다 맨 처음을 제외하고는 바로 직전에 주식을 샀을 때보다 가격이 올라갔을 때만 사기로 했다.
가장 긴 증가하는 수열을 구하는 방법은 두 가지 시간 복잡도로 나눌 수 있는데, 모든 수열을 찾는 O(N^2)이 걸리는 방법과, 하나의 리스트를 사용하여 인덱스를 찾아가며 교환하는 O(NlogN)이 걸리는 방법이 있다. 문제의 최대 입력을 생각해보면 100 * 10000 * 100 = 100억 이므로 시간 제한 5초안에 통과하려면 무조건 O(NlogN)이 걸리는 방법을 사용해야 한다.
O(NlogN)은 이분탐색을 통해서 구하는 방법인데 경계값을 찾는 방법 중 lower bound를 사용한다. lower bound는 현재 값보다 크거나 같은 값을 찾는 알고리즘인데, 위의 알고리즘에서 기록을 하게 되는 리스트에서 경계 값을 찾아서 해당 위치의 값을 바꾸어야 하기 때문에 사용한다. 이에 따라서 매 테스트 케이스마다 첫번째 값을 추가하고 모든 값을 lower bound를 통해서 리스트에 어떤 부분에 추가해야할지 찾아본다. 이 때, 리스트는 정렬된 상태이므로 리스트의 마지막 값보다 크다면 리스트에 그냥 추가하고 그 외의 경우 특정 위치를 변경한다.
이 방법을 통해서 가장 긴 증가하는 수열의 길이를 찾을 수 있다. 문제에서는 가장 긴 증가하는 수열의 길이가 k보다 크거나 같으면 1을 출력하고 그 외의 경우 0을 출력하면 되므로 이를 구현하면 답을 받을 수 있다.
코드 구현하기
- 모든 테스트 케이스 당 아래를 반복한다.
- 입력을 처리하고 입력되는 1차원 배열을 저장한다.
- 배열을 탐사하면서 기록할 리스트를 만들고 저장된 배열의 0번째 인덱스의 수를 리스트에 추가한다.
- 배열을 1번째 인덱스 부터 탐사하며 리스트의 어떤 인덱스에 삽입될지 탐색한다.
- 탐색이 끝났다면 리스트의 마지막 인덱스인 수보다 현재 수가 큰지 확인하고 크다면 리스트의 마지막에 추가한다. 그 외의 경우에는 찾은 인덱스의 값보다 현재 값이 작다면 현재 값을 해당 인덱스에 있는 값과 교체한다.
- 모든 연산이 끝나면 찾은 리스트의 길이와 k를 비교하여 답을 출력한다.
풀이
import java.io.*;
import java.util.*;
public class Main {
public static class FastReader {
BufferedReader br;
StringTokenizer st;
public FastReader() {
br = new BufferedReader(new InputStreamReader(System.in));
}
String next() {
while (st == null || !st.hasMoreElements()) {
try {
st = new StringTokenizer(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
return st.nextToken();
}
int nextInt() {
return Integer.parseInt(next());
}
}
static int TC;
static int[] nums;
public static void main(String[] args) {
FastReader fr = new FastReader();
TC = fr.nextInt();
for (int i = 0; i < TC; i++) {
int n = fr.nextInt();
int k = fr.nextInt();
nums = new int[n];
for (int j = 0; j < n; j++) {
nums[j] = fr.nextInt();
}
ArrayList<Integer> list = new ArrayList<>();
list.add(nums[0]);
for (int j = 1; j < n; j++) {
int low = 0;
int high = list.size() - 1;
int mid = 0;
while (low <= high) {
mid = (low + high) / 2;
if (nums[j] > list.get(mid)) {
low = mid + 1;
} else {
high = mid - 1;
}
}
if (list.get(list.size() - 1) < nums[j]) {
list.add(nums[j]);
} else {
list.set(low, nums[j]);
}
}
System.out.println("Case #" + (i + 1) + "\n" + (list.size() >= k ? 1 : 0));
}
}
}
'Problem Solving > BOJ' 카테고리의 다른 글
백준 2842번 : 집배원 한상덕 [Java] (0) | 2025.02.23 |
---|---|
백준 1938번 : 통나무 옮기기 [Java] (0) | 2025.02.21 |
백준 2515번 : 전시장 [Java] (0) | 2025.02.20 |
백준 15685번 : 드래곤 커브 [Java] (1) | 2025.02.19 |
백준 9328번 : 열쇠 [Java] (0) | 2025.02.18 |