문제
- 문제 링크
BOJ 30621 - 어? 금지
N개의 시각에 대해 수열 tN,bN,cN이 주어진다.
성우가 규칙을 지키는 선에서 대회장에 줄 수 있는 최종 혼란의 최댓값을 구해보자.
TL : 1 sec, ML : 1024 MB
1≤N≤100,000 1≤ti,bi,ci≤109 ti−1<ti; bi≤ti
알고리즘 분류
- 다이나믹 프로그래밍 (dp)
- 이분 탐색 (binary_search)
풀이
어떤 시각 ti에서, 선택할 수 있는 분기 방향을 생각해보자.
이는 다음과 같을 것이다.
'어?'를 외치지 않는다.
지금부터 '어?'를 처음 외친다.
두 번째 경우의 연장선인데, (ti−bi)부터 지금까지 '어?'를 외친 적이 없는 경우 '어?'를 외친다.
3가지의 상태를 따로 관리할 필요 없이, 최댓값만을 취하면 된다.
이에 따라 아래와 같이 점화식을 정의하자.
그럼 각 세가지 분기 방향에 대해 다음과 같이 전이식을 정리할 수 있다.
dp[i] = dp[i−1] dp[i] = ci (ti−bi)보다 작은 첫 인덱스를 prev_idx라 할 때, dp[i] = dp[prev_idx]+ci
한편, prev_idx를 찾을 때 현재 i에서 하나씩 내려가보며 찾는 것을 생각할 수 있다.
이 경우 prev_idx를 찾는 데에 O(N)의 시간이 걸릴 테고, N≤100,000으로 시간 초과를 피할 수 없다.
문제의 입력 제한에서, ti−1<ti임을 확인하자.
ti가 단조 증가 하므로 이분 탐색을 이용해 prev_idx를 O(logN)에 찾을 수 있다.
따라서, 문제를 O(NlogN)의 시간 복잡도로 해결할 수 있다.
전체 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #include<bits/stdc++.h> using ll = long long; using namespace std; int main() { ios_base::sync_with_stdio(0); cin.tie(0); int n; cin >> n; vector <int> t(n), b(n); for (int& i : t) cin >> i; for (int& i : b) cin >> i; vector <ll> dp(n); cin >> dp[0]; for (int i(1); i < n; i++) { ll c; cin >> c; int prev_idx(lower_bound(t.begin(), t.begin() + i + 1, t[i] - b[i]) - t.begin()); dp[i] = max(dp[i - 1], c); if (!!~--prev_idx) dp[i] = max(dp[i], dp[prev_idx] + c); } cout << dp[n - 1]; } | cs |
comment
끝
'Problem Solving > Baekjoon Online Judge (Gold)' 카테고리의 다른 글
백준 27728 - 개구리와 쿼리 (C++) (0) | 2024.01.06 |
---|---|
백준 30869 - 빨리 기다리기 (C++) (1) | 2023.12.04 |
백준 30622 - Rush & Slash (C++) (1) | 2023.11.14 |
백준 30461 - 낚시 (C++) (1) | 2023.11.06 |
백준 30464 - 시간낭비 (C++) (3) | 2023.11.06 |