Loading [MathJax]/jax/output/CommonHTML/jax.js

문제링크

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(2apv[j]pv[i]+dp[j]+apv[j]2pv[j]+apv[i]2+bpv[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

+ Recent posts