728x90
https://www.acmicpc.net/problem/2515
2515번: 전시장
첫째 줄에는 그림의 개수 N (1 ≤ N ≤ 300,000)과 판매가능 그림을 정의하는 1이상의 정수 S가 빈칸을 사이에 두고 주어진다. 다음 이어지는 N개의 줄 각각에는 한 그림의 높이와 가격을 나타내는 정
www.acmicpc.net
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Comparator;
import java.util.StringTokenizer;
/**
*
*/
public class bj2516 {
static int[][] paint;
static int N, S;
static int[][] DP;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
S = Integer.parseInt(st.nextToken());
paint = new int[N+1][2];
for(int n=1;n<=N;n++){
st = new StringTokenizer(br.readLine());
paint[n][0] = Integer.parseInt(st.nextToken());
paint[n][1] = Integer.parseInt(st.nextToken());
}
// 가장 긴 증가하는 수열 찾기 문제랑 비슷하다고 생각했고..
// ->> 어짜피 그림 위치는 바꿀 수 있고 가장 많이 보이려면 어찌됐든 오름차순으로 보여야 되니까
// 입력이 상대적으로 많으니까 가장 긴 증가하는 수열에서 시간을 줄이기 위해 썼던 방법인 이분탐색을 활용함.
Arrays.sort(paint, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
if(o1[0] == o2[0]) return o2[1]-o1[1];
else return o1[0]-o2[0];
}
});
//높이는 오름차순, 가격은 내림차순으로 정렬.
/*
for(int[] a : paint){
for(int k : a){
System.out.print(k + " ");
}
System.out.println();
}
*/
DP = new int[N+1][2];
for (int n = 1; n <= N; n++) {
if (paint[n][0] - DP[n - 1][1] >= S) { //차이가 S이상이면 일단 더함.
DP[n][0] = DP[n - 1][0] + paint[n][1]; //최고 금액 저장.
DP[n][1] = paint[n][0]; // 직전 추가된 높이 저장.
} else {
int prev; // n과의 높이 차이가 S이상인 지점
prev = binary_search(n);
if (DP[n - 1][0] > DP[prev][0] + paint[n][1]) { //현재 그림을 선택하지 않는 경우
DP[n][0] = DP[n - 1][0];
DP[n][1] = DP[n - 1][1];
} else { //현재 그림을 선택하는 경우
DP[n][0] = DP[prev][0] + paint[n][1];
DP[n][1] = paint[n][0];
}
}
for(int i=0;i<DP.length;i++){
System.out.print(Arrays.toString(DP[i]));
}
System.out.println();
}
System.out.println(DP[N][0]);
}
public static int binary_search(int n){
int low = 0;
int high = n - 1;
while (low <= high){
int mid = (low + high) / 2;
if (paint[n][0] - paint[mid][0] >= S) low = mid + 1;
else high = mid - 1;
}
return high;
}
}
|
[cs |
[풀이]
위에도 말했다시피 가장 긴 증가하는 수열 (LIS) 문제를 응용해서 이분 탐색을 해야겠다고 생각했다.
같은 스터디를 하는 오빠 한분이 전시장의 모든 길이를 포함하는 배열을 만들어 빈 공간을 DP[idx-1]로 채워주는 형식의 선형 방법을 통해
인덱스를 저장해줬는데 훠어어어얼씬 시간이 적게 나와서 신기했다.
또 다른 오빠 한분은 직접 이분탐색을 구현하는 대신 binarysearch라는 메소드를 사용했는데, 이 메소드의 경우 bound를 사용할 수 없다고 한다. 따라서 이 때 메소드의 값이 마이너스가 되는 것을 방지하기 위해 마이너스가 될 겨우 2를 빼고 부호를 변경해주는 방법을 사용했는데, 굉장히 신선했다.
이런거 써도 되나 싶지만 어짜피 내 티스토리는 나만 본당 ㅎ
헿
그럼 끝!!
728x90
댓글