문제
- 문제 링크
BOJ 17526 - Star Trek
1에서 $n$으로 이동하려고 한다.
문제에 정의된 비용을 따를 때, 가장 최소의 비용으로 이동하는 경우를 구해보자.
TL : $1$ sec, ML : $512$ MB
$3 ≤ n ≤ 100,000$ $1 ≤ s ≤ 100,000$ $0 ≤ p ≤ 1,000,000,000$
알고리즘 분류
- 다이나믹 프로그래밍(dp)
- 볼록 껍질을 이용한 최적화(convex hull trick)
- 누적 합(prefix sum)
풀이
임의의 지점으로 가는 데엔 결국 그 이전 지점들 중에 어디에서 환승하냐가 관건이다.
두 지점 간 거리를 빠르게 계산하기 위해 누적 합( $p[]$ )을 이용하자.
이후, 간단하게 점화식을 만들어 볼 수 있다.
$dp[i]$ : $1$ ~ $i$까지 이동하는 데에 드는 최소 비용
$dp[i] = min(dp[i], dp[j] + a[j] + b[j] * (p[i] - p[j]))$ {$1 ≤ j < i$}
$p[i] = x$로 하는 직선의 방정식으로 정리해보면
$f(x) = b[j] * x - b[j] * p[j] + a[j] + dp[j]$
CHT를 적용할 꼴이 나왔지만, 단조성이 딱히 없어 보인다.
따라서 리차오 트리를 이용해 각 $p[i]$에 대한 최솟값 쿼리를 날려주면 $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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | #include<bits/stdc++.h> #define ll long long #define N 100001 using namespace std; struct L { ll p, q; inline ll f(ll x) { return p * x + q; } }; struct Node { ll l, r, s, e; L ln; }; vector <Node> T; ll M(1e18), c[N], dp[N]; int n, i, a[N], b[N]; void in() { ios_base::sync_with_stdio(0); cin.tie(0); cin >> n; for (i = 2; i <= n; i++) cin >> c[i], c[i] += c[i - 1]; for (i = 1; i < n; i++) cin >> a[i] >> b[i]; } void push(L q, ll n) { ll s(T[n].s), e(T[n].e), m((s + e) >> 1); L p = T[n].ln; if (p.f(s) > q.f(s)) swap(p, q); if (p.f(e) <= q.f(e)) { T[n].ln = p; return; } if (p.f(m) < q.f(m)) { T[n].ln = p; if (!~T[n].r) T[n].r = T.size(), T.push_back({ -1, -1, m + 1, e, { 0, M } }); push(q, T[n].r); return; } T[n].ln = q; if (!~T[n].l) T[n].l = T.size(), T.push_back({ -1, -1, s, m, { 0, M } }); push(p, T[n].l); } ll Q(ll x, ll n) { return !~n ? M : min(T[n].ln.f(x), Q(x, ((x << 1) <= T[n].s + T[n].e ? T[n].l : T[n].r))); } void sv() { T.push_back({ -1, -1, 0, (ll)1e9, {0, M} }); for (i = 2; i <= n; i++) push({ b[i - 1], dp[i - 1] + a[i - 1] - b[i - 1] * c[i - 1] }, 0), dp[i] = Q(c[i], 0); cout << dp[n]; } int main() { in(); sv(); } | cs |
comment
이후 기여 탭에서 봤는데
식을 좀 더 잘 다듬어 보면, 단조성을 찾을 수 있다고 한다.
'Problem Solving > Baekjoon Online Judge (Diamond)' 카테고리의 다른 글
백준 17429 - 국제 메시 기구 (C++) (0) | 2023.04.29 |
---|---|
백준 13519 - 트리와 쿼리 10 (C++) (0) | 2023.04.27 |
백준 6171 - 땅따먹기 (C++) (0) | 2023.04.27 |
백준 15249 - Building Bridges (C++) (0) | 2023.04.26 |
백준 14180 - 배열의 특징 (C++) (0) | 2023.04.26 |