結果
| 問題 | No.703 ゴミ拾い Easy | 
| コンテスト | |
| ユーザー |  | 
| 提出日時 | 2021-10-13 20:13:20 | 
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) | 
| 結果 | 
                                AC
                                 
                             | 
| 実行時間 | 125 ms / 1,500 ms | 
| コード長 | 4,363 bytes | 
| コンパイル時間 | 2,386 ms | 
| コンパイル使用メモリ | 204,436 KB | 
| 最終ジャッジ日時 | 2025-01-25 00:21:18 | 
| ジャッジサーバーID (参考情報) | judge1 / judge1 | 
(要ログイン)
| ファイルパターン | 結果 | 
|---|---|
| sample | AC * 4 | 
| other | AC * 46 | 
ソースコード
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
// --------------------------------------------------------
template<class T> bool chmin(T& a, const T b) { if (b < a) { a = b; return 1; } return 0; }
#define FOR(i,l,r) for (ll i = (l); i < (r); ++i)
#define REP(i,n) FOR(i,0,n)
using VB = vector<bool>;
using VLL = vector<ll>;
// --------------------------------------------------------
// References:
//   <https://smijake3.hatenablog.com/entry/2018/06/16/144548>
//   <https://tjkendev.github.io/procon-library/cpp/convex_hull_trick/li_chao_tree.html>
//   <https://cp-algorithms.com/geometry/convex_hull_trick.html>
/**
 * @brief Convex Hull Trick (Li-Chao Segment Tree)
 * 
 */
struct LiChaoSegtree {
    static constexpr ll INF1 = 1e9;   // 葉ノード以外のダミー座標
    static constexpr ll INF2 = 1e18;  // 最小値クエリの初期値
    int N;          // 座標の数
    vector<ll> xs, p, q;  // 座標・傾き・接線
    vector<bool> used;    // ノードが一度も使用されていなければ false
    LiChaoSegtree(int n, const vector<ll>& ps) {
        N = 1;
        while (N < n) N <<= 1;
        xs.resize(2*N);
        p.resize(2*N);
        q.resize(2*N);
        used.resize(2*N);
        for (int i = 0; i < n; i++) xs[i] = ps[i];
        for (int i = n; i < 2*N; i++) xs[i] = INF1;
        for (int i = 0; i < 2*N; i++) used[i] = false;
    }
    // 区間 [l,r) に対する直線 (a,b) の追加処理
    void _add_line(ll a, ll b, int k, int l, int r) {
        while (l < r) {
            if(not used[k]) {
                used[k] = true; p[k] = a; q[k] = b;
                return;
            }
            int m = (l + r) / 2;
            ll lx = xs[l], mx = xs[m], rx = xs[r-1];
            ll pk = p[k], qk = q[k];
            bool left  = (a*lx + b < pk*lx + qk);
            bool mid   = (a*mx + b < pk*mx + qk);
            bool right = (a*rx + b < pk*rx + qk);
            if (left && right) {  // 直線 (a,b) が全勝
                p[k] = a;
                q[k] = b;
                return;
            } else if (not left && not right) {  // 直線 (p,q) が全勝
                return;
            } else if (mid) {  // swap することで探索区間を片側だけに減らすテク
                swap(p[k], a);
                swap(q[k], b);
            } else if (left != mid) {  // [l,m) で直線 (a,b) が勝つ部分あり
                k = 2*k + 1; r = m;
            } else {  // [m,r) で直線 (a,b) が勝つ部分あり
                k = 2*k + 2; l = m;
            }
        }
    }
    // 直線 (a,b) の追加
    void add_line(ll a, ll b) { _add_line(a, b, 0, 0, N); }
    // 区間 [x_l, x_r) に対する線分 (a,b) の追加
    void add_segment_line(ll a, ll b, int l, int r) {
        int L = l + N, R = r + N;
        int sz = 1;
        while (L < R) {
            if (L & 1) {
                _add_line(a, b, L-1, l, l+sz);
                L++; l += sz;
            }
            if (R & 1) {
                R--; r -= sz;
                _add_line(a, b, R-1, r, r+sz);
            }
            L >>= 1; R >>= 1;
            sz <<= 1;
        }
    }
    // i 番目の座標に対する最小値を返す
    ll query(int i) {
        ll x = xs[i];
        int k = i + (N - 1);
        ll res = (used[k] ? p[k]*x + q[k] : INF2);
        while (k > 0) {
            k = (k - 1) / 2;
            if (used[k]) chmin(res, p[k]*x + q[k]);
        }
        return res;
    }
};
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed << setprecision(15);
    ll N; cin >> N;
    VLL a(N); REP(i,N) cin >> a[i];
    VLL x(N); REP(i,N) cin >> x[i];
    VLL y(N); REP(i,N) cin >> y[i];
    LiChaoSegtree cht(N, a);
    // dp[i] :=  左から i 番目までを考えた時の最小コスト
    // ----- 遷移式 --> Convex Hull Trick -----
    // dp[0] = 0
    // dp[i] = min_{0<=j<i} { dp[j] + (x[j] - a[i-1])^2 + y[j]^2 }
    //       = min_{0<=j<i} { -2*x[j]*a[i-1] + (dp[j] + x[j]^2 + y[j]^2) } + a[i-1]^2
    //       (1<=i<=N)
    VLL dp(N+1); dp[0] = 0;
    REP(i,N) {
        cht.add_line(-2*x[i], dp[i] + x[i]*x[i] + y[i]*y[i]);
        dp[i+1] = cht.query(i) + a[i]*a[i];
    }
    ll ans = dp[N];
    cout << ans << endl;
    return 0;
}
// Verify: https://yukicoder.me/problems/no/703
            
            
            
        