문제
https://www.acmicpc.net/problem/3020
풀이
해당 구간의 높이에 따라 부딪히는 석순과 종유석의 개수를 체크해주기만 하면 된다. 가령 첫번째 구간에선 높이가 1이상인 것들은 전부 파괴하므로 석순은 길이가 1이상, 종유석은 전체높이 - 1 이상인 것들을 전부 찾아준다. 이 때 브루트포스로 하면 너비 20만에 높이 50만 짜리는 무조건 시간초과가 나므로 이분탐색의 upper_bound & lower_bound를 이용하여 해결해준다.#include <stdio.h> #include <iostream> #include <algorithm> #include <math.h> using namespace std; // 이진 탐색으로 구현한 lower_bound long long lower_bound(int arr[], int n, int key){ int start = 0; int end = n; while(end - start > 0){ int mid = (start + end) / 2; if(arr[mid] < key){ start = mid + 1; } else if(arr[mid] >= key){ end = mid; } } return end; } // 이진 탐색으로 구현한 upper_bound long long upper_bound(int arr[], int n, int key){ int start = 0; int end = n; while(end - start > 0){ int mid = (start + end) / 2; if(arr[mid] <= key){ start = mid + 1; } else if(arr[mid] > key){ end = mid; } } return end; } int main(){ int bot[100010], top[100010]; int N, H; cin >> N >> H; int less_destroy = N, less_cnt = 1; for(int i = 0; i < N / 2; i++){ cin >> bot[i] >> top[i]; } sort(bot, bot + N / 2); sort(top, top + N / 2); // ex) 1번째 구간 -> 길이가 1 이상 -> 석순은 길이가 1 이상이며 종유석은 길이가 H - 1 이상인 것. for(int i = 1; i <= H; i++){ // 석순에 대한 범위 int low_bot_dest = lower_bound(bot, N / 2, i); int up_bot_dest = N / 2; // 종유석에 대한 범위 int low_top_dest = lower_bound(top, N / 2, H - i + 1); int up_top_dest = N / 2; int bot_cnt = up_bot_dest - low_bot_dest; int top_cnt = up_top_dest - low_top_dest; // 이전에 찾은 최소 파괴 수가 현재 파괴한 수와 같으면 개수를 추가한다. if(less_destroy == bot_cnt + top_cnt) less_cnt++; // 그렇지 않으면 상황에 따라 갱신하거나 그대로 둔다. else{ if(less_destroy > bot_cnt + top_cnt){ less_destroy = bot_cnt + top_cnt; less_cnt = 1; } } } cout << less_destroy << " " << less_cnt; return 0; }
댓글
댓글 쓰기