제출 #1317865

#제출 시각아이디문제언어결과실행 시간메모리
1317865anngelaBuilding Bridges (CEOI17_building)C++20
100 / 100
39 ms11280 KiB
// https://oj.uz/problem/view/CEOI17_building // AC 38 ms #include <set> #include <algorithm> #include <iostream> #include <climits> using namespace std; using ll = long long; const int MAXN = 1e5 + 5; const ll INF = 1e18 + 5; ll n, h[MAXN], w[MAXN]; ll dp[MAXN]; ll sp[MAXN]; void Read() { cin >> n; for (int i = 1; i <= n; ++i) cin >> h[i]; for (int i = 1; i <= n; ++i) { cin >> w[i]; sp[i] = sp[i - 1] + w[i]; } } template <class T> struct Line { T m, k; mutable T x; bool is_min; Line(T m, T k, T x, bool is_min = false) : m {m}, k {k}, is_min {is_min} {} // pentru maxime - convex hull cu concavitatea in sus - panta trebuie sa cresca in hull // pentru minime - convex hull cu concavitatea in jos - panta trebuie sa sada in hull bool operator<(const Line& line) const { return is_min ? m > line.m : m < line.m; } bool operator<(T x) const { return this->x < x; } }; template <class T, bool is_min> struct CHT : multiset<Line<T>, less<>> { static const ll INF = LLONG_MAX; ll div(T a, T b) { // "floor division" daca rezultatul impartirii este < 0 si exista rest, atunci scade 1 return a / b - ((a ^ b) < 0 && a % b); } // determina abscisa x de intersectie intre dreptele *a si *b // returneaza true daca linia *b trebuie stearsa bool isect(auto a, auto b) { // x este abscisa de intersectie intre dreapta curenta *a si urmatoarea *b if (b == this->end()) // nu exista linia b (deci a nu trebuie in pericol sa fie stearsa) { a->x = INF; return false; } if (a->m == b->m) { if (a->k < b->k) a->x = is_min ? INF : -INF; else a->x = is_min ? -INF : INF; } else a->x = div(b->k - a->k, a->m - b->m); // daca nu sunt paralele aflam abscisa de intersectie dintre *a si *b return a->x >= b->x; // daca *a si *b se intersecteaza la dreapta intersectiei *b cu *c(urmatoarea), atunci b trebuie eliminata } void add(T m, T k) { auto c = this->emplace(m, k, 0, is_min), b = c++, a = b; // acum a si b indica noua dreapta, c - urmatoarea din container // incercam sa eliminam linii din dreapta liniei noi (linia noua *b poate cauza stergeri in dreapta sa) while (isect(b, c)) // cat timp *c (urmatoarea dupa *b) trebuie eliminata c = this->erase(c); // se elimina (iteratorul b ramane pe loc, c merge spre dreapta) // linia noua *b de asemenea ar putea fi eliminata if (a != this->begin() && isect(--a, b)) isect(a, b = this->erase(b)); // b devine urmatorul nesters // linia noua ar putea sa duca la stergerea altor linii din stanga sa while ((b = a) != this->begin() && (--a)->x >= b->x) isect(a, this->erase(b)); // sterge b si calculeaza intersectia liniei a cu noul b } ll query(T x) { auto l = *this->lower_bound(x); // operator<(int x) din Line return l.m * x + l.k; } }; void Solve() { CHT<ll, true> hull; fill(dp + 1, dp + n + 1, INF); dp[1] = 0; for (int i = 1; i <= n; ++i) { if (i > 1) dp[i] = hull.query(h[i]) + h[i] * h[i] + sp[i - 1]; hull.add(-2 * h[i], dp[i] + h[i] * h[i] - sp[i]); } cout << dp[n]; } int main() { ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0); Read(); Solve(); return 0; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...