Автор задачі: | Антон Перебийніс (Pcheloveks) |
Підготовлено: | Антон Перебийніс (Pcheloveks) |
Розбір: | Антон Перебийніс (Pcheloveks) |
Розв'язання
Припустимо, що ми вибрали відрізок довжини len = R - L + 1. Тоді існує два можливих випадки розподілу тузів: якщо len \geq k_L і якщо len < k_L.
: len \geq k_L
У цьому випадку результат дорівнює \sum_{i = L}^{R} a_i + k_L * x_L. Використавши префіксні суми, перепишемо формулу у вигляді p_R - p_{L - 1} + k_L * x_L, де p_i = \sum_{j = 1}^{i} a_j. Можна помітити, що цей вираз складається з двох частин: одна залежить від — p_R, друга залежить лише від — -p_{L - 1} + k_L * x_L.
Отже, зафіксувавши праву межу , отримаємо формулу для максимального результату серед усіх відрізків, що закінчуються в точці : p_R + \max_{R - L + 1 \geq k_L}(-p_{L - 1} + k_L * x_L). Для фіксованого ця умова виконується для всіх R \geq L + k_L - 1.
Тому, ітеруючись по зліва направо, будемо додавати подію "активації" відповідного у момент L + k_L - 1 і підтримувати максимум значень -p_{L - 1} + k_L * x_L серед усіх активних .
len < k_L
У цьому випадку результат дорівнює \sum_{i = L}^{R} a_i + (R - L + 1) * x_L. Перепишемо формулу через префіксні суми:
p_R - p_{L - 1} + (R - L + 1) * x_L = p_R - p_{L - 1} + x_L * R + x_L * (L - 1).
Зафіксуємо і винесемо частини, що не залежать від :
\max_{R - L + 1 < k_L}(p_R - p_{L - 1} + x_L * R + x_L * (L - 1)) = p_R + \max_{R - L + 1 < k_L}(x_L * R + x_L * (L - 1) - p_{L - 1}).
Можна побачити, що залежність виразу під максимумом від є лінійною і має вигляд y = k * R + b, де k = x_L і b = x_L * (L - 1) - p_{L - 1}.
Таким чином, ми отримуємо класичну задачу пошуку максимуму серед лінійних функцій, яка розв'язується методом Convex Hull Trick, з тією відмінністю, що кожна лінійна функція існує не для всіх значень .
Для фіксованого ця функція існує лише для R \in [L, L + k_L - 1).
Для коректної обробки таких обмежень використаємо дерево відрізків. Кожну лінійну функцію додаємо у всі вершини дерева, які повністю покривають відповідний інтервал [L, L + k_L - 1).
Щоб отримати відповідь для конкретного , спускаємося по дереву до листа, що відповідає цій точці, і беремо максимум значень серед усіх Convex Hull Trick, які зберігаються у вершинах на цьому шляху.
Для ефективної реалізації: попередньо зберігаємо всі запити на додавання ліній і всі запити на отримання максимуму, сортуємо їх, додаємо всі лінії у відповідні вершини дерева.
У кожній вершині значення , для яких відбуваються запити, також будуть відсортовані. Оскільки в межах однієї вершини немає додаткових обмежень на існування ліній, можна застосувати стандартний Convex Hull Trick із монотонними запитами.
Часова складність алгоритму становить O(N \log_{2} N), оскільки кожна з ліній і кожен з запитів додається у log_{2} N вершин дерева відрізків, а обробка в кожній вершині виконується за лінійний час.
Перша частина алгоритму (випадок len \geq k_L) працює за .
Код розв'язку
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <bitset>
#include <map>
#include <vector>
#include <set>
#include <algorithm>
#define endl '\n'
using namespace std;
FILE* stream;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair < int, int > pii;
typedef pair < ld, ld > pdd;
const long long DIM = 500007;
const ld eps = 1e-12;
const long long INF = 1e18;
const long long Bsize = 450;
const int mod = 998244353;
const long long NUMSZ = 500;
struct line {
ll k, b;
line() {
k = 0;
b = 0;
}
line(ll k_, ll b_) {
k = k_;
b = b_;
}
ll get(ll x) {
return (ll)k * (ll)x + (ll)b;
}
};
ll intersection(const line& l1, const line& l2) {
ll a = l2.b - l1.b;
ll b = l1.k - l2.k;
return a / b - ((a ^ b) < 0 && a % b);
}
class convexHull {
public:
void init(int sz) {
d.clear();
d.resize(2 * sz + 5);
L = sz;
R = sz;
}
void add(line l) {
if (R - L > 0 && d[R - 1].k == l.k) {
if (d[R - 1].b >= l.b) return;
R--;
}
while (R - L > 1 &&
intersection(d[R - 2], d[R - 1]) >= intersection(d[R - 2], l)) {
R--;
}
d[R++] = l;
}
ll query(ll x) {
if (R - L == 0) return -INF;
while (R - L > 1 && intersection(d[L], d[L + 1]) <= x) {
L++;
}
return d[L].get(x);
}
void clear() {
d.clear();
}
private:
int L, R;
vector < line > d;
};
ll res[DIM];
class convexHullTree {
public:
void init(int sz_) {
sz = sz_;
T.resize(4 * sz + 7);
}
void addLine(int L, int R, line l) {
addLine(0, 1, sz, L, R, l);
}
void addQuery(int pos, ll x) {
addQuery(0, 1, sz, pos, x);
}
void proces() {
convexHull c;
for (auto ver : T) {
c.init(2 * ver.l.size());
for (auto l : ver.l) c.add(l);
for (auto x : ver.x) {
res[x] = max(res[x], c.query(x));
}
c.clear();
}
}
private:
void addLine(int v, int tl, int tr, int L, int R, line l) {
if (L <= tl && tr <= R) {
T[v].l.push_back(l);
return;
}
if (tl > R || tr < L) return;
int tm = (tl + tr) >> 1;
addLine(2 * v + 1, tl, tm, L, R, l);
addLine(2 * v + 2, tm + 1, tr, L, R, l);
}
void addQuery(int v, int tl, int tr, int pos, ll x) {
T[v].x.push_back(x);
if (tl == tr) {
return;
}
int tm = (tl + tr) >> 1;
if (pos <= tm) {
addQuery(2 * v + 1, tl, tm, pos, x);
}
else {
addQuery(2 * v + 2, tm + 1, tr, pos, x);
}
}
struct node {
vector < line > l;
vector < ll > x;
};
int sz;
vector < node > T;
};
struct queryLine {
line l;
ll L, R;
};
bool cmp(queryLine l1, queryLine l2) {
return l1.l.k < l2.l.k;
}
vector < queryLine > Lq;
int main() {
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#ifdef _DEBUG
freopen_s(&stream, "input.txt", "r", stdin);
freopen_s(&stream, "output.txt", "w", stdout);
#endif
int n;
cin >> n;
vector < ll > a(n + 1), k(n + 1), x(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) cin >> k[i];
for (int i = 1; i <= n; i++) cin >> x[i];
vector < ll > p = a;
for (int i = 1; i <= n; i++) {
p[i] += p[i - 1];
if (k[i] == 0) {
k[i] = 1;
x[i] = 0;
}
}
ll ans = -1e18;
ll mxExp = -INF;
vector < ll > events(n + 1, -INF);
for (int i = 1; i <= n; i++) {
if(i + k[i] - 1 <= n) events[i + k[i] - 1] = max(events[i + k[i] - 1], -p[i - 1] + k[i] * x[i]);
Lq.push_back({ {x[i], -(ll)(i - 1) * x[i] - p[i - 1]}, i, i + k[i] - 1 });
mxExp = max(mxExp, events[i]);
ans = max(ans, mxExp + p[i]);
}
convexHullTree t;
t.init(n);
sort(Lq.begin(), Lq.end(), cmp);
for (auto x : Lq) {
if (x.L > x.R) continue;
t.addLine(x.L, x.R, x.l);
}
for (int i = 1; i <= n; i++) {
t.addQuery(i, i);
}
for (int i = 1; i <= n; i++) res[i] = -INF;
t.proces();
for (int i = 1; i <= n; i++) {
ans = max(ans, p[i] + res[i]);
}
cout << ans << endl;
return 0;
}