문제링크
https://www.acmicpc.net/problem/4008
4008번: 특공대
입력은 세 줄로 구성된다. 첫 번째 줄에 전체 병사들 수인 양의 정수 n이 주어진다. 두 번째 줄에 특공대의 조정된 전투력 계산 등식의 계수인 세 정수 a, b, c가 주어진다. 마지막 줄에 병사들 1, 2,
www.acmicpc.net
풀이
- dp[i]: i 번 병사들로 특공대를 만들었을 때 조정된 전체 전투력의 최댓값이라고 하고
- v[i],pv[i] 는 각각 병사의 전투력과 그 누적합 배열이라 하자
- dp[i] 는 i 번 병사가 속해있는 특공대가 앞의 몇명을 포함하느냐에 따라서 생각해 볼 수 있고 그를 나타낸 점화식은 다음과 같다.
- dp[i]=max0<=j<i(dp[j]+a∗(pv[i]−pv[j])2+b∗(pv[i]−pv[j])+c)
- 이를 정리하면 다음과 같다.
- dp[i]=max0<=j<i(−2a∗pv[j]∗pv[i]+dp[j]+a∗pv[j]2−pv[j]+a∗pv[i]2+b∗pv[i]+c)
- 컨벡스헐트릭(Convex hull trick)을 적용할 수 있는 점화식 형태이며 pv 배열또한 단조성을 가지고 있으므로 O(N) 에 해결할 수 있다.
코드
- 시간복잡도: O(N)
#include <bits/stdc++.h> using namespace std; #define all(v) (v).begin(), (v).end() #define rall(v) (v).rbegin(), (v).rend() struct line { long long m, c; long long eval(long long x) { return m * x + c; } long double intersectX(line l) { return (long double) (c - l.c) / (l.m - m); } }; int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int N; cin >> N; long long a, b, c; cin >> a >> b >> c; vector<long long> v(N + 1, 0), pv(N + 1, 0); for (int i = 1; i <= N; ++i) { cin >> v[i]; pv[i] = v[i] + pv[i - 1]; } deque<line> dq; dq.push_front({0, 0}); long long ans = 0; for (int i = 1; i <= N; i++) { while (dq.size() >= 2 && dq[0].eval(pv[i]) <= dq[1].eval(pv[i])) dq.pop_front(); ans = dq.front().eval(pv[i]); line cur = {-2LL * a * pv[i], a * pv[i] * pv[i] - b * pv[i] + ans +a * pv[i] * pv[i] + b * pv[i] + c }; while (dq.size() >= 2 && cur.intersectX(dq.back()) <= dq.back().intersectX(dq[dq.size() - 2])) dq.pop_back(); dq.push_back(cur); } cout << ans + a * pv[N] * pv[N] + b * pv[N] + c << '\n'; }
728x90
'PS > BOJ' 카테고리의 다른 글
백준 3640번: 제독 (0) | 2022.03.07 |
---|---|
백준 13263번: 나무 자르기 (0) | 2022.03.06 |
백준 16978번: 수열과 쿼리 22 (0) | 2022.03.02 |
백준 13548번: 수열과 쿼리 6 (0) | 2022.02.28 |
백준 1420번: 학교 가지마! (0) | 2022.02.26 |