문제
https://programmers.co.kr/learn/courses/30/lessons/42891
걸린 시간
02 : 13 : 35
풀이
C++
#include <string>
#include <vector>
#include <queue>
typedef long long ll;
using namespace std;
int solution(vector<int> food_times, ll k) {
int answer = 0;
vector<int> empty(food_times.size(), 0);
priority_queue<pair<int, int>> pq;
for(int i = 0; i < food_times.size(); i++)
pq.push(make_pair(-food_times[i], i));
ll K = 0, T = 0; // K : 먹방이 진행된 시간, T : 전체적으로 줄어든 음식의 시간
while(!pq.empty()){
ll left = -pq.top().first;
int num = pq.top().second;
ll size = pq.size();
left -= T;
if(K+left*size > k) break;
pq.pop();
empty[num] = 1;
if(left == 0) continue;
K += left*size;
T += left;
}
if(pq.empty()){
answer = -1;
return answer;
}
int i = 0;
int time = (k-K)%pq.size()+1;
while(time){
if(!empty[i]) time--;
i++;
}
answer = i;
return answer;
}
1초씩 food_times 의 값을 줄여나가는 무식한 방법은 입력값의 범위가 큰 효율성 테스트를 통과할 수 없다. 즉, k초 후의 상태를 얼마나 빠르게 알 수 있는지가 관건이다.
회전판이 계속해서 돌며 무지 앞에 음식을 가져다 주는데 다 먹은 음식이 생겨날 경우 해당 음식을 건너뛰고 다음 음식을 섭취해야 한다.
핵심 아이디어는 이 시점을 기준으로 시간대를 나누는 것이다.
현재 회전판에 올려져 있는 음식을 차례대로 먹었을 때 제일 먼저 바닥이 나는 음식은 food_times 값이 제일 작은 번호의 음식이다.
제일 작은 food_times 의 값이 0이 될 때 까지 회전판이 돌았다고 가정하면 지나간 시간은 제일 작은 값
* 남은 음식의 개수
가 된다.
이 과정을 k초를 넘기지 않을 때 까지 반복해주면 정답은 현재 시간과, 한번 더 반복하였을 때의 시간 사이에 존재하게 된다.
구현 과정은 최소힙에 food_times 의 값을 음식의 번호와 함께 저장한 후 하나씩 꺼내어 먹방이 진행된 시간 K
와 전체적으로 줄어든 음식의 시간 T
그리고 다 먹은 음식 empty
배열을 갱신해준다. 힙에 남아있는 원소가 없다면 모든 음식을 다 먹은 것이므로 -1 를 출력한다. 그렇지 않으면 k초가 되기까지 남은 시간을 현재 남은 음식의 개수로 나누어 준 후, 남은 음식들 중에서 나머지+1(구하려는 값) 번째의 음식 번호를 정답으로 반환한다.
먹방이 진행된 시간 K
값을 갱신하는 과정에서 최대 1억 * 20만 의 곱셈이 있을 수 있으므로 산술 오버플로가 일어날 수 있음에 유의하여 관련된 변수의 자료형을 모두 long long 으로 선언해주어야 한다.
'programmers' 카테고리의 다른 글
programmers Level 2 주차 요금 계산 (0) | 2022.04.24 |
---|---|
programmers Level 2 k진수에서 소수 개수 구하기 (0) | 2022.04.24 |
programmers Level 2 순위 검색 (0) | 2021.09.18 |
programmers Level 3 모두 0으로 만들기 (0) | 2021.04.16 |
2021 KAKAO BLIND RECRUITMENT 1차 코딩테스트 (1, 2번) (0) | 2020.09.12 |
댓글