結果
| 問題 |
No.703 ゴミ拾い Easy
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2019-11-15 02:11:12 |
| 言語 | C++14 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 140 ms / 1,500 ms |
| コード長 | 3,059 bytes |
| コンパイル時間 | 1,988 ms |
| コンパイル使用メモリ | 175,136 KB |
| 実行使用メモリ | 21,272 KB |
| 最終ジャッジ日時 | 2025-01-02 14:23:35 |
| 合計ジャッジ時間 | 7,071 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 4 |
| other | AC * 46 |
ソースコード
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
// https://lumakernel.github.io/ecasdqina/dynamic-programming/convex-hull-trick/LiChaoTree
// 最小化: Comp = less<T>, 最大化: Comp = greater<T>
template<class T = ll, class Comp = less<T> >
struct LiChaoTree {
using Line = pair<T, T>;
static inline T f(const Line& line, T x) { return line.first * x + line.second; }
static Comp comp;
int n;
vector<Line> data;
vector<int> used;
vector<T> xs;
private:
// [l, r)
void add(int l, int r, const Line& line) {
int l0 = l, r0 = r;
int sz = 1;
for (l += n, r += n; l < r; l >>= 1, r >>= 1, sz <<= 1) {
if (l & 1) add(l, l0, l0 + sz, line), l0 += sz, ++l;
if (r & 1) --r, r0 -= sz, add(r, r0, r0 + sz, line);
}
}
void add(int k, int l, int r, Line line) {
if (!used[k]) {
used[k] = true;
data[k] = line;
return;
}
T cur_ly = f(data[k], xs[l]), cur_ry = f(data[k], xs[r - 1]);
T nex_ly = f(line, xs[l]), nex_ry = f(line, xs[r - 1]);
if (comp(cur_ly, nex_ly) && comp(cur_ry, nex_ry)) return;
if (comp(nex_ly, cur_ly) && comp(nex_ry, cur_ry)) {
data[k] = line;
return;
}
if (r - l == 1) return;
int m = (l + r) >> 1;
if (comp(cur_ly, nex_ly)) swap(data[k], line);
if (comp(f(line, xs[m]), f(data[k], xs[m]))) {
swap(data[k], line);
add((k << 1) | 1, m, r, line);
} else {
add(k << 1, l, m, line);
}
}
public:
// 前処理(事前にクエリのx座標を渡す必要あり)
void addx(T x) { xs.emplace_back(x); }
void prebuild() {
sort(xs.begin(), xs.end());
xs.erase(unique(xs.begin(), xs.end()), xs.end());
int sz = xs.size();
n = 1;
while (n < sz) n <<= 1;
xs.resize(n, xs.back());
data.resize(n << 1);
used.resize(n << 1);
}
// 直線追加: ax + b
void add(T a, T b) { add(0, n, Line(a, b)); }
// 線分追加: ax + b (l <= x <= r)
void add(T a, T b, T l, T r) {
int li = lower_bound(xs.begin(), xs.end(), l) - xs.begin();
int ri = upper_bound(xs.begin(), xs.end(), r) - xs.begin();
add(li, ri, Line(a, b));
}
// ax+bが最小/最大となる(a,b)を取得
Line get(T x) {
int idx = -1;
for (int i = lower_bound(xs.begin(), xs.end(), x) - xs.begin() + n; i > 0; i >>= 1) {
if (!used[i]) continue;
if (idx == -1 || comp(f(data[i], x), f(data[idx], x))) idx = i;
}
assert(idx > 0 && idx < (n << 1));
return data[idx];
}
// ax+bの最小/最大値を取得
T query(T x) { return f(get(x), x); }
};
template<class T, class Comp>
Comp LiChaoTree<T, Comp>::comp;
constexpr ll INF = 1e18;
int main() {
cin.tie(0);
ios::sync_with_stdio(false);
int n;
cin >> n;
vector<ll> a(n), x(n), y(n);
LiChaoTree<> lct;
for (int i = 0; i < n; i++) {
cin >> a[i];
lct.addx(a[i]);
}
lct.prebuild();
for (int i = 0; i < n; i++) cin >> x[i];
for (int i = 0; i < n; i++) cin >> y[i];
vector<ll> dp(n + 1, INF);
dp[0] = 0;
for (int i = 0; i < n; i++) {
lct.add(-2 * x[i], x[i] * x[i] + y[i] * y[i] + dp[i]);
dp[i + 1] = lct.query(a[i]) + a[i] * a[i];
}
cout << dp[n] << "\n";
return 0;
}