LOJ 3156: "NOI2019" ルートホーム

トピックポータル:LOJの#3156

質問の説明の意味:

ある\(N- \)ポイント\(m個\)有向グラフのエッジは、両側の重みがあり、(P_I \)\\(Q_I \)(\ (P_I <Q_I \)の場合)を示している\ (P_I \)時間始点の手前には、\(Q_I \) このエッジの終わりに達するまでの時間。

あなたは、ルートを計画する必要があるので、最初から\(1 \)最終到達するために、このルートに沿ってドットを開始\(N \)ドット。

順次側を通る経路であると仮定する(\ {A_1、A_2、\ ldots、a_k \} \)\、確保することが必要である(\ I-Q_ {A_。1} {} \ {a_iをルP_})\を
この経路の費用は、\(\ displaystyle Q_ {a_k} + \ sum_ {i = 2} ^ {K} F(P_ {a_iを} -q_ {A_ {I-1}})+ F(P_ {A_1 })\) ここで\(F(X)= \ mathrm {A} + X ^ 2 \ mathrm {B} + X \ mathrm {C} \)

あなたはこの最低価格の最小出力のあなたの計画ルートのコストを作成する必要があります。

ソリューション:

二次関数のコスト間の移動は、それは見かけのスロープDP最適化モデルとなります。

検討([\ mathrm {F} \ \ i])と第1貫通表さ\(Iは\)の後にエッジ- \()\ \ F SUM({。Q_ 1} a_j P_ A_ {} {J})のジェーンの式:

\ [\ \ mathrm {整列}開始{F} [I] - = \ MIN_ {y_j = X_I、q_j \ルP_I} \ {\ mathrm {F} [J] + \ mathrm {A}(P_I-q_j) ^ 2 + \ mathrm {B}(P_I-q_j)+ \ mathrm {C} \} \\&= \ MIN_ {y_j = X_I、q_j \ルP_I} \ {\ mathrm {F} [J] + \ mathrm {A} P_I ^ 2-2 \ mathrm {A} p_iq_j + \ mathrm {A} q_j ^ 2 + \ mathrm {B} p_i- \ mathrm {B} q_j + \ mathrm {C} \} \\&= \ MIN_ { y_j = X_I、q_j \ルP_I} \ {\ mathrm {F} [J] + \ mathrm {A} q_j ^ 2- \ mathrm {B} q_j-2 \ mathrm {A} p_iq_j \} + \ mathrm { } P_I ^ 2 + \ mathrm {B} P_I + \ mathrm {C} \端{整列} \]

発現の勾配が明らかであり、\(X \)座標\(Q_I \)、\ (Y \)は、座標(\ \ mathrm {F} [ i]は+ \ mathrm {A} Q_I ^ 2- \ mathrm {B} Q_I \)、そう\(\ mathrm {D} _i = \ mathrm {A} P_I ^ 2 + \ mathrm {B} P_I + \ mathrm {C} \)
次いで(\ \ displaystyle \ mathrm {F } [I] = \ mathrm _i} + {D \ {y_j = MIN_ X_I、Q_j \ルP_I} \ {2- y_j \ mathrm p_ix_j {A} \} \)

調査2法的転移点\(J \)\(K \)(\ (X - jが<X_K \) )、転移点\(J \)転移点よりも\(K \)が好ましい場合にのみ:

\ [\開始{整列} y_j-2 \ mathrm {A} p_ix_j&<Y_K-2 \ mathrm {A} \\ 2 \ mathrm {A} P_I(X_K-X - jが)&<Y_K-y_j \\\ FRACを{p_ix_k Y_K-y_j} {X_K-X - jが}&> 2 \ mathrm {A}整列P_I \端{} \]

数が数範囲よりも大きいので、そう凸包を維持します。

更新順番に従って、便宜上、なお\(P_I \)右の傾きが増加しているように、小から大に、それはすぐに追加凸包を更新していませんが、対応のターンまで待つ必要があります\(P_I \)ときその後、追加します。

以下は、コード、時間複雑さがある(\ mathcal {O}(N-M + + \ Q max)を\)\します

#include <cstdio>
#include <algorithm>
#include <vector>

typedef double db;
const int MN = 100005, MM = 200005, MQ = 1005;

int N, M, _A, _B, _C, Ans = 0x3f3f3f3f;
int d[MN], eu[MM], ev[MM], ep[MM], eq[MM];
std::vector<int> vp[MQ], vq[MQ];
int X[MM], Y[MM], f[MM];
int _stk[MM], *stk[MN], _l[MN], _r[MN];

inline db Slope(int i, int j) {
    if (X[i] == X[j]) return Y[i] == Y[j] ? 0 : Y[i] < Y[j] ? 1e99 : -1e99;
    return (db)(Y[j] - Y[i]) / (X[j] - X[i]);
}

int main() {
    freopen("route.in", "r", stdin);
    freopen("route.out", "w", stdout);
    scanf("%d%d%d%d%d", &N, &M, &_A, &_B, &_C);
    ev[0] = 1, vq[0].push_back(0), ++d[1];
    for (int i = 1; i <= M; ++i) {
        scanf("%d%d%d%d", &eu[i], &ev[i], &ep[i], &eq[i]);
        vp[ep[i]].push_back(i);
        vq[eq[i]].push_back(i);
        ++d[ev[i]];
    }
    stk[0] = _stk;
    for (int i = 1; i <= N; ++i) stk[i] = stk[i - 1] + d[i - 1], _l[i] = 1;
    for (int t = 0; t <= 1000; ++t) {
        for (auto i : vq[t]) {
            int u = ev[i], *st = stk[u], l = _l[u], &r = _r[u];
            while (l < r && Slope(st[r - 1], st[r]) > Slope(st[r], i)) --r;
            st[++r] = i;
            if (u == N && Ans > f[i] + eq[i]) Ans = f[i] + eq[i];
        }
        for (auto i : vp[t]) {
            int u = eu[i], *st = stk[u], &l = _l[u], r = _r[u];
            while (l < r && Slope(st[l], st[l + 1]) < 2 * _A * t) ++l;
            if (l <= r) f[i] = Y[st[l]] - 2 * _A * t * X[st[l]] + _A * t * t + _B * t + _C;
            else f[i] = 0x3f3f3f3f;
            X[i] = eq[i], Y[i] = f[i] + _A * eq[i] * eq[i] - _B * eq[i];
        }
    }
    printf("%d\n", Ans);
    return 0;
}

おすすめ

転載: www.cnblogs.com/PinkRabbit/p/NOI2019D1T1.html