본문 바로가기

알고리즘/백준

15961 - 회전 초밥[G4]

목차

     

    문제

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

     

    15961번: 회전 초밥

    첫 번째 줄에는 회전 초밥 벨트에 놓인 접시의 수 N, 초밥의 가짓수 d, 연속해서 먹는 접시의 수 k, 쿠폰 번호 c가 각각 하나의 빈 칸을 사이에 두고 주어진다. 단, 2 ≤ N ≤ 3,000,000, 2 ≤ d ≤ 3,000, 2

    www.acmicpc.net

     

    풀이

    초밥의 전체 배열이 주어지면, 연속으로 k개를 먹는다고 할 때 얼마나 다양한 접시를 먹을 수 있는가? 최대값을 구하는 문제이다.

     

    사실 이 문제는 슬라이딩 윈도우나, 투 포인터를 사용하는 것이 가장 이상적이다.

    하지만 이번 풀이에는 이와 유사하게 HashMap을 사용하여 풀이해보았다.

    근본적인 로직 자체는 비슷하고, O(3N) 정도의 시간 복잡도를 가질 테였다(해시 충돌이나 이런 걸 배제하고)

     

    최악의 엣지 케이스의 경우 N = 300만이었다. 

    일반적으로 1초 = 1000만번의 연산으로 가정할 때 거의 시간 초과에 가깝다고 생각했다.

     

    결과는 거의 아슬하게 성공. 자세한 내용은 코드를 참고할 것.

     

    코드

     

    import java.util.*;
    import java.io.*;
    
    public class Main {
    	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    
        public static void main(String[] args) throws IOException {
        	int res = 0;
        	StringTokenizer st = new StringTokenizer(br.readLine());
        	int N = Integer.parseInt(st.nextToken()); //접시
        	int d = Integer.parseInt(st.nextToken()); //초밥수
        	int k = Integer.parseInt(st.nextToken()); //연속접시
        	int c = Integer.parseInt(st.nextToken()); //쿠폰번호
        	
        	int dish[] = new int[N];
        	for(int i = 0; i < N; i++) dish[i] = Integer.parseInt(br.readLine());
        	
        	
        	//초기 입력
        	HashMap<Integer, Integer> takes = new HashMap<>();
        	for(int i = 0; i < k; i++) {
        		int now = dish[i];
        		if(takes.containsKey(now)) takes.put(now, takes.get(now) + 1);
        		else takes.put(now, 1); 
        	}
        	res = takes.size(); 
        	if(!takes.containsKey(c)) res++;
        	
        	//메인 로직
        	for(int i = 0; i < N + k; i++) {
        		int last = dish[i % N]; //이전 접시
        		int now = dish[(i + k) % N]; //새로운 접시
        		
        		//제거
        		if(takes.containsKey(last)) {
        			if(takes.get(last) == 1) takes.remove(last);
        			else takes.put(last, takes.get(last) - 1);
        		}
        		
        		//추가
        		if(takes.containsKey(now)) takes.put(now, takes.get(now) + 1);
        		else takes.put(now, 1);
    
        		int nowRes = takes.size();
        		if(takes.containsKey(c)) nowRes++; //쿠폰번호
        		
        		res = Math.max(res, nowRes);
        	}
        	
        	System.out.println(res);
        }
    }

    '알고리즘 > 백준' 카테고리의 다른 글

    단어 뒤집기 2 - 17413[S3]  (0) 2024.03.21
    경로 찾기 - 11403[S1]  (1) 2024.01.09
    11047 - 동전 0[S4]  (0) 2024.01.03
    1504 - 특정한 최단 경로[G4]  (0) 2024.01.02
    MooTube - 15591[G5]  (0) 2023.12.30