문제
https://www.acmicpc.net/problem/1756
풀이
뭔가 문제 자체는 어렵지는 않은데 시간이 오래 걸렸다. 문제를 딱 보면 이중 for문은 당연히 30만 * 30만으로 시간초과가 날 것이다. 이분탐색으로 풀어야하나 싶었는데 아쉽게도 오븐이 정렬된 형태가 아니다. 문제를 잘 보면 어떤 반죽이 특정 위치에서 걸려버리면 그 밑은 값이 어떻게 나오든 상관이 없어진다. 가령
5
6
4
3
6
2
3
지름의 크기가 위와 같을 때 반죽 4짜리는 4번째에서 걸려버린다. 이게 뭘 의미하냐, 예를 들어 깊이가 3인 곳의 지름은 4인데, 그 밑인 깊이가 4, 5, 6, 7은 지름이 4보다 커도 어차피 통과할 수 있는 반죽은 지름이 4이하인 반죽이다. 즉 특정 위치의 밑에 있는 것들은 그 위치의 지름보다 작거나 같아야한다. 따라서 위의 지름을 아래와 같이 바꿀 수 있다.
5
5
4
3
3
2
2
수학적인 아이디어는 위와 같고 이제 만들어진 반죽을 차례로 돌면서 오븐에 넣어보자. 문제에선 3 2 5 짜리 반죽을 넣었다. 이 때, 맨 밑에서부터 탐색해야 중간에 걸렸는지 알 수 있게 되므로 밑에서부터 탐색하도록 만들자. 그렇다면 반죽 3은 6번째에 걸려서 5 위치에 있을테고, 반죽 2는 그 위에 올려질 것이다. 마지막 반죽 5는 3번째에 걸려서 2 위치에 있을 것이다. (문제의 힌트를 보면 이해가 될 것이다.)
즉 맨 아래서부터 탐색하되, 어디서 걸리는지 체크하는 시작점은 최근 반죽을 넣었을 때 걸리는 지점이 될 것이다.
#include <stdio.h> #include <iostream> #include <vector> #include <math.h> #include <algorithm> using namespace std; long blocked; int main(){ int D, N; cin >> D >> N; long dough[300001]; long oven[300001]; blocked = D + 1; long mini = 1000000001; long minoven = 1000000001; for(int i = 1; i <= D; i++){ long t; cin >> t; minoven = min(t, minoven); oven[i] = minoven; } for(int i = 1; i <= N; i++){ cin >> dough[i]; mini = min(dough[i], mini); } // 해당 반죽이 이전 반죽보다 작으면 그 위에 살포시 얹으면 된다. 그리고 걸린 마지막 지점은 위로 한칸 올라가게 된다. for(int i = 1; i <= N; i++){ if(i != 1 && dough[i] <= dough[i - 1]){ blocked--; } // 이전 반죽보다 크다면 else{ // 맨 마지막으로 걸린 지점부터 맨 위까지 쭉 탐색해서 for(int j = blocked - 1; j >= 1; j--){ // 오븐보다 반죽이 더 클 경우 위로 한칸씩 계속 올려준다. 즉 반죽이 통과되다가 걸리는 지점을 밑에서부터 찾아주는 것이다. if(oven[j] < dough[i]){ blocked--; } // 쭉 올리다 오븐의 반지름이 더 커지게 되면 해당 지점까지는 통과된 것이다. else break; } // 특정 위치에서 걸린 것이므로 반죽은 그 위치보다 한칸 위에 얹혀있을 것이다. blocked--; } } // 걸린 지점이 0보다 작거나 같아지게 되면 피자가 오븐 안에 전부 들어가지 못한 것이다.
if(blocked <= 0) blocked = 0; cout << blocked; return 0; }
댓글
댓글 쓰기