본문 바로가기
알고리즘/BAEKJOON

[백준] 23326 홍익 투어리스트 (Java)

by kyeee2 2022. 4. 27.

[23326 홍익 투어리스트]

난이도: 골드3

 

23326번: 홍익 투어리스트

도현이는 홍익 투어리스트가 되어 홍익대학교를 견학하려고 한다. 홍익대학교는 $N$개의 구역이 원형으로 배치된 모습이다. $1$번 구역에서 시계 방향으로 각각 $2$번, ... , $N$번 구역이 존재하고,

www.acmicpc.net

문제

입력

출력


[아이디어]

구현이 중요한 문제같다.

TreeSet을 활용하여 명소의 위치를 관리해주었는데, 이 이유는 3번 쿼리를 빠르게 다루기 위해서이다.

 

처음에 명소의 위치를 초기화해준 후 쿼리문을 수행하는데, 1번 쿼리는 단순히 set에 넣고 빼주기만 하면 된다.

2번 쿼리는 위치를 이동시켜주는데 now = (now + n - 1) % N + 1 이 식을 활용하면 된다.

이 때, now의 최대 값은 5십만이고 n 이 최대 10억이기 때문에 int의 범위를 벗어나지 않는다.

 

가장 시간 초과가 나기 쉬운 부분이 3번 쿼리문이다.

우선 set이 비어있다면 명소에 도달할 수 없기 때문에 -1을 출력해준다. 또한, 현재 위치가 명소에 들어있다면 0을 출력한다. 그 다음 시계방향에서 가장 가까운 명소를 찾는 방법인데, 나는 TreeSet에 있는 함수인 ceiling()을 활용하였다.

ceiling(num) 은 num이상의 수들 중 가장 작은 수를 반환하고, 없다면 null을 반환하는 함수이다.

이 함수로 현재 위치보다 큰 번호의 명소를 찾아 거리의 차이(idx - now)를 계산해주었고, 없다면 명소 중 가장 작은 번호의 명소로 차이(N - now + spots.first())를 계산해주었다.

 


[JAVA 코드]

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

public class Main {
	
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static StringBuilder output = new StringBuilder();
	static StringTokenizer tokens;
	
	static int N, Q, now;
	static TreeSet<Integer> spots = new TreeSet<>(); // 명소 위치 저장

	public static void main(String[] args) throws IOException {
		tokens = new StringTokenizer(br.readLine());
		N = Integer.parseInt(tokens.nextToken());
		Q = Integer.parseInt(tokens.nextToken());
		
		tokens = new StringTokenizer(br.readLine());
		for(int i = 1; i <= N; i++) {
			if(Integer.parseInt(tokens.nextToken()) == 1) spots.add(i);
		}
		
		// 현재 위치 초기화
		now = 1;
		for(int t = 0; t < Q; t++) {
			tokens = new StringTokenizer(br.readLine());
			
			switch(tokens.nextToken()) {
			case "1":
				// n번 구역 명소 지정 또는 지정x
				int n = Integer.parseInt(tokens.nextToken());
				if(spots.contains(n)) spots.remove(n);
				else		 		  spots.add(n);
				break;
			case "2":
				// n만큼 이동하기
				n = Integer.parseInt(tokens.nextToken());
				now = (now + n - 1) % N + 1;
				break;
			case "3":
				if(spots.isEmpty()) {
					// 명소가 없는 경우
					output.append("-1\n");
				} else if(spots.contains(now)) {
					// 지금 위치가 명소인 경우
					output.append("0\n");
				} else {
					// 지금 위치보다 큰 인덱스 중 현재 위치와 가장 가까운 인덱스
					Integer idx = spots.ceiling(now);
					if(idx != null) {
						// 오른쪽에 명소가 존재하는 경우
						output.append((idx - now) + "\n");
					} else {
						// 오른쪽에 없으면 가장 작은 명소의 위치로 계산
						output.append((N - now + spots.first()) + "\n");
					}
				}
				break;
			}
		}
		System.out.println(output);
	}

}

댓글