본문 바로가기

Hub Algorithm/IMOS 알고리즘 ( 누적합 )

[BOJ] 백준 3020 : 개똥벌레 (java)

728x90

🧪 3020 개똥벌레


난이도 : 🌟 골드 5
유형 : IMOS 알고리즘 ( 누적합 )

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

 

📝 문제


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

아래 그림은 길이가 14미터이고 높이가 5미터인 동굴이다. (예제 그림)

 

이 개똥벌레는 장애물을 피하지 않는다. 자신이 지나갈 구간을 정한 다음 일직선으로 지나가면서 만나는 모든 장애물을 파괴한다.

위의 그림에서 4번째 구간으로 개똥벌레가 날아간다면 파괴해야하는 장애물의 수는 총 여덟개이다. (4번째 구간은 길이가 3인 석순과 길이가 4인 석순의 중간지점을 말한다)

 

하지만, 첫 번째 구간이나 다섯 번째 구간으로 날아간다면 개똥벌레는 장애물 일곱개만 파괴하면 된다.

동굴의 크기와 높이, 모든 장애물의 크기가 주어진다. 이때, 개똥벌레가 파괴해야하는 장애물의 최솟값과 그러한 구간이 총 몇 개 있는지 구하는 프로그램을 작성하시오.

 

입력

 

첫째 줄에 N과 H가 주어진다. N은 항상 짝수이다. (2 ≤ N ≤ 200,000, 2 ≤ H ≤ 500,000)

다음 N개 줄에는 장애물의 크기가 순서대로 주어진다. 장애물의 크기는 H보다 작은 양수이다.

 

출력

 

첫째 줄에 개똥벌레가 파괴해야 하는 장애물의 최솟값과 그러한 구간의 수를 공백으로 구분하여 출력한다.

 

🧐 핵심 로직 


1) Imos 알고리즘을 활용한 누적합 방법으로 풀이했다.

 

2) 누적합을 구하기 위한 카운팅 배열을 만든다.

    2 - a) 석순의 경우 stalactites 배열에 카운팅하고, 종유석의 경우는 stalagmites 배열에 카운팅하는데 이때, stalagmites 배열은 기존 동굴의 높이인 h 에서 빼고 + 1을 한 높이의 인덱스에 값을 카운팅한다.

 

3) 카운팅 배열을 토대로 누적합을 계산하는데 이때, 석순은 카운팅 되어있는 인덱스 기준 아래쪽으로 나있기 때문에 위쪽부터 누적합을 더해나가고, 종유석은 인덱스 기준 위쪽이기 때문에 아래부터 누적합을 채워나간다.

 

4) 최소 장애물 수와 최소 개수를 초기화 해두고 장애물 수가 최소 장애물 수 보다 작다면 최소 장애물 수 를 현재의 장애물 수로 변경하고 최소 개수를 1로 초기화 한다.

    4 - a) 만약, 장애물 수와 최소 장애물 수가 같다면 최소 개수를 늘려준다.

 

💻 최종 코드 (324 ms)


import java.io.*;
import java.util.*;

public class Main {

    static int n, h;
    public static void main(String[] args) throws IOException {

//        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedReader br = new BufferedReader(new FileReader("input.txt"));
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = Integer.parseInt(st.nextToken());
        h = Integer.parseInt(st.nextToken());

        int[] stalactites = new int[h + 1];
        int[] stalagmites = new int[h + 1];
        for (int i = 0; i < n / 2; i++) {
            int stalactitesHeight = Integer.parseInt(br.readLine());
            int stalagmitesHeight = Integer.parseInt(br.readLine());

            stalactites[stalactitesHeight]++;
            stalagmites[h - stalagmitesHeight + 1]++;
        }

        for (int i = h - 1; i >= 1; i--) {
            stalactites[i] += stalactites[i + 1];
        }

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

        int minObstacles = Integer.MAX_VALUE;
        int minCount = 0;
        for (int i = 1; i <= h; i++) {
            int obstacles = stalactites[i] + stalagmites[i];

            if (obstacles < minObstacles) {
                minObstacles = obstacles;
                minCount = 1;
            } else if (obstacles == minObstacles) {
                minCount++;
            }
        }

        System.out.println(minObstacles + " " + minCount);

        br.close();
    }
}