post image post image post image post image post image post image post image post image

https://www.acmicpc.net/problem/3020

 

3020번: 개똥벌레

개똥벌레 한 마리가 장애물(석순과 종유석)로 가득찬 동굴에 들어갔다. 동굴의 길이는 N미터이고, 높이는 H미터이다. (N은 짝수) 첫 번째 장애물은 항상 석순이고, 그 다음에는 종유석과 석순이

www.acmicpc.net

 

종유석 배열과 석순 배열을 따로 선언하고 값을 저장해준 뒤, 두 배열을 정렬하여 이분탐색을 활용하여 문제를 해결했다.

두 배열이 오름차순 정렬되어 있으므로  (각각의 배열의 크기 - 이분탐색으로 찾은 인덱스 위치 값) 을 계산해 현재 장애물의 개수를 체크했다.

 

시간복잡도는 h번 순회하면서 이분탐색을 수행하므로 O(h * logN) 이다.

 

#include <iostream>
#include <algorithm>

#define F_BOUND floor_arr, floor_arr + mid
#define C_BOUND ceil_arr, ceil_arr + mid
using namespace std;

int floor_arr[100'000];
int ceil_arr[100'000];

int main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int n, h, tmp, mid, cnt;
	int min_val = 1e9, min_val_cnt = 0;

	cin >> n >> h;
	for (int i = 0; i < n; i++) {
		cin >> tmp;
        //i가 홀수일 시 천장 배열에 i/2위치에 넣기
        //i/2위치에 넣는 이유는 배열을 짝수배열 홀수배열 두개로 나눴기때문
		if (i & 1) ceil_arr[i>>1] = tmp;
        //i가 홀수일 시 바닥 배열에 i/2위치에 넣기
		else floor_arr[i>>1] = tmp;
	}
	
    //각각의 배열의 크기
	mid = n / 2;

	//이분탐색을 위한 정렬
	sort(F_BOUND);
	sort(C_BOUND);

	for (int i = 0; i < h; i++) {
		cnt = 0;
        //바닥 배열에서 높이가 i를 초과하는 원소의 수만큼 더해줌
		cnt += (mid - (upper_bound(F_BOUND, i) - floor_arr));
        //천장 배열에서 높이가 (h - i) 이상인 원소의 수만큼 더해줌
		cnt += (mid - (lower_bound(C_BOUND, h - i) - ceil_arr));

		//최소값 갱신 및 개수 체크
		if (min_val >= cnt) {
			if (min_val > cnt) {
				min_val = cnt;
				min_val_cnt = 0;
			}
			min_val_cnt++;
		}
	}
	
	cout << min_val << ' ' << min_val_cnt << '\n';
	return 0;
}
메모리: 2800 kb 시간: 60 ms

 

추가로 이 문제는 누적합으로도 풀 수 있다.

누적합 풀이는 아래 글을 참고했다.

https://blog.naver.com/jinhan814/222252619895

 

[BOJ] 3020번 - 개똥벌레

http://boj.kr/3020 sol1) prefix sum 2021 KAKAO BLIND RECRUITMENT의 E번 문제였...

blog.naver.com

 

#include <iostream>
#include <algorithm>

#define BOUND arr, arr + h
using namespace std;

int arr[500'001];

int main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int n, h, tmp, mid, cnt;
	int min_val, min_val_cnt;

	cin >> n >> h;
	for (int i = 0; i < n; i++) {
		cin >> tmp;
		if (i & 1) arr[h - tmp]++, arr[h]--;
		else arr[0]++, arr[tmp]--;
	}

	for (int i = 1; i <= h; i++) {
		arr[i] += arr[i - 1];
	}

	min_val = *min_element(BOUND);
	min_val_cnt = count(BOUND, min_val);

	cout << min_val << ' ' << min_val_cnt << '\n';
	return 0;
}
메모리: 3972 kb 시간: 24 ms

 

누적합 풀이가 훨씬 간결하고 성능적으로도 우수하다.

이분탐색 풀이는 시간복잡도가 O(h * logN) 이었는데 반해 누적합풀이는 O(n) 의 시간복잡도를 갖는다.

'컴퓨터 사이언스 > 1고리즘' 카테고리의 다른 글

백준 9251 : LCS  (0) 2021.07.31
백준 2631 : 줄세우기  (0) 2021.07.31
백준 2225 : 합분해  (0) 2021.07.31
백준 1504 : 특정한 최단 경로  (0) 2021.07.30
백준 5214 : 환승  (0) 2021.07.28

+ Recent posts