알고리즘/백준
15961 - 회전 초밥[G4]
블랑v
2024. 1. 7. 23:46
문제
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);
}
}