[백준/Java] 23326

민선규·2023년 8월 22일

코딩테스트

목록 보기
3/20
post-thumbnail

홍익 투어리스트

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

문제

도현이는 홍익 투어리스트가 되어 홍익대학교를 견학하려고 한다. 홍익대학교는 NN개의 구역이 원형으로 배치된 모습이다. 11번 구역에서 시계 방향으로 각각 22번, ... , NN번 구역이 존재하고, NN번 구역에서 시계 방향으로 한 칸 더 갈 경우 11번 구역으로 도착한다.

홍익대학교에는 명소가 존재한다. 도현이는 알찬 투어를 위해 명소만을 방문하려 한다. 도현이는
11번 구역에 서있다.

도현이를 위해 다음과 같은 쿼리를 수행하는 프로그램을 작성해보자.

11 ii : ii번 구역이 명소가 아니었다면 명소로 지정되고, 명소였다면 지정이 풀리게 된다. (1iN1 \leq i \leq N)

22 xx : 도현이가 시계방향으로 xx만큼 이동한다. (1x1091 \leq x \leq 10^9)

33 : 도현이가 명소에 도달하기 위해 시계방향으로 최소 몇 칸 움직여야 하는 지 출력한다. 명소가 존재하지 않는 경우 1-1을 출력한다.

입력

첫째 줄에 구역의 개수 NN (1N5000001 \leq N \leq 500\,000)과 쿼리의 개수 QQ (1Q1000001 \leq Q \leq 100\,000)가 정수로 주어진다.

둘째 줄에 길이 NN의 수열 AA가 주어진다. ii번째 구역이 명소라면 AiA_i11, 그렇지 않다면 00이다.

셋째 줄부터 QQ줄에 걸쳐 본문의 쿼리가 주어진다. 33번 쿼리는 하나 이상 존재한다.

출력

33번 쿼리가 주어질 때마다 해당 쿼리의 값을 출력한다.

문제 풀이 방법 및 해설

N의 크기와 Q의 크기를 명심하면서 풀이를 하였다. 결국 이 문제에서 원하는 것은 현재 도현이의 위치로 부터 가장 가까운 명소를 찾는 것인데, 무조건 시계 방향으로만 돌아야 하는 것이 제한이다. 그래서 명소를 관리하는 TreeSet 자료구조를 사용하였다. 그 이유로는 TreeSet에서는 X보다 큰 값 중에 가장 작은 값을 반환해주는 함수를 제공해주기 때문이다.

11 ii의 경우에는 TreeSet에 저장되어 있으면 삭제하고, 저장되어 있지 않으면 추가만 해주면 된다.

22 xx 경우에는 도현이의 위치를 옮겨주어야 하는데 아무리 큰 수가 오더라고 결국 한 반퀴를 돌게 되면 제자리 이기 때문에 나머지를 계산해 최종적으로 움직여야 하는 칸을 계산하고 크기를 넘을 경우 N으로 나누어 주면 된다.

33 경우에는 우선 명소가 있는 지 체크를 한다. 그리고 현재 내 자리가 명소인지도 확인을 하고 그래도 값이 없다면 현재 위치 기준으로 마지막 장소 까지 명소를 확인하고 마지막으로 처음부터 현재 위치 기준으로 전 장소 까지 확인을 하면 된다.

그렇게 하면 전체 시간복잡도는 Q Log N이 되는데 이는 대략 100,000 18 = 1,800,000 이므로 시간제한에도 널널하다.

풀이 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Optional;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class Main {

    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        StringBuilder sb = new StringBuilder();
        TreeSet<Integer> set = new TreeSet<>();

        int N = Integer.parseInt(st.nextToken());
        int Q = Integer.parseInt(st.nextToken());
        int pos = 1;

        st = new StringTokenizer(br.readLine());
        for(int i = 1 ; i <= N ;i++){
            int value = Integer.parseInt(st.nextToken());
            if(value == 1) {
                set.add(i);
            }
        }

        for(int i = 0; i < Q ; i++){
            st = new StringTokenizer(br.readLine());
            int number = Integer.parseInt(st.nextToken());

            if(number == 1){
                int idx = Integer.parseInt(st.nextToken());
                if(set.contains(idx)){
                    set.remove(idx);
                }else{
                    set.add(idx);
                }
            }else if(number == 2){
                int move = Integer.parseInt(st.nextToken()) % N;
                pos += move;
                if(pos > N){
                    pos %= N;
                }
            }else{
                if(set.isEmpty()){
                    sb.append("-1").append("\n");
                    continue;
                }

                if(set.contains(pos)){
                    sb.append(0).append("\n");
                    continue;
                }

                Integer front = set.higher(pos);
                Integer back = set.higher(0);

                if(front != null){
                    sb.append(front-pos).append("\n");
                }else{
                    sb.append(N-pos+back).append("\n");
                }
            }
        }
        System.out.println(sb);
    }
}

0개의 댓글