AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

AcWing 1093. 仓库建设    原题链接    困难

作者: 作者的头像   白流雪 ,  2025-06-10 20:40:20 · 江苏 ,  所有人可见 ,  阅读 5


1



算法

(斜率优化dp) $O(n)$

记 dp[i] 表示在第 $i$ 个工厂建立仓库产生的最小费用。

状态转移:

$$ dp[i] = \min\{dp[j] + w(j, i) \big| 1 \leqslant j < i\} + c_i $$

$ \begin{aligned} w(j, i) &= p_{j+1} \times (x_i - x_{j+1}) + p_{j+2} \times (x_i - x_{j+2}) + \cdots + p_{i-1} \times (x_i - x_{i-1}) + p_i \times (x_i - x_i)\\\ &= x_i \times \sum_{k=j+1}^i p_k - \sum_{k=j+1}^{i} p_kx_k \end{aligned} $

我们用 $P_i$ 表示 $p_1 + p_2 + \cdots + p_i$,用 $Q_i$ 表示 $p_1x_1 + p_2x_2 + \cdots + p_ix_i$
那么 $w(j, i) = x_i(P_i-P_j) - (Q_i-Q_j)$

于是,$dp[i] = \min\{-P_jx_i + (dp[j] + Q_j)\} + P_ix_i - Q_i + c_i$

注意到斜率 $-P_j$ 单调递减,所以可以暴力移指针;另外,横坐标 $x_i$ 单调递增,所以可以用单调队列来维护凸包

还需注意以下坑点:

  • 这里的 $dp$ 是假定在第 $i$ 个工厂建仓库,但最后一个工厂如果没有成品的话,就不需要建仓库了。

C++ 代码

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;
using P = pair<ll, ll>;

template<class T=int>
inline T read() {
    T num = 0;
    int neg = 1;
    char c = getchar_unlocked();
    while (!isdigit(c) and c != '-') {
        c = getchar_unlocked();
    } 
    if (c == '-') neg = -1;
    else num = c-'0';
    c = getchar_unlocked();
    while (isdigit(c)) {
        num = (num<<1)+(num<<3)+(c^48);
        c = getchar_unlocked();
    }
    return num*neg;
}

// 求最小值
struct CHT {
    deque<P> d;
    void add(ll a, ll b) {
        while (d.size() >= 2) {
            auto [a1, b1] = d[d.size()-1];
            auto [a0, b0] = d[d.size()-2];
            if ((b0-b1)*(a-a1) < (b1-b)*(a1-a0)) break;
            d.pop_back();
        }
        d.emplace_back(a, b);
    }
    ll get(ll x) {
        while (d.size() >= 2) {
            auto [a0, b0] = d[0];
            auto [a1, b1] = d[1];
            if (a0*x+b0 < a1*x+b1) break;
            d.pop_front();
        }
        auto [a, b] = d[0];
        return a*x+b;
    }
};

int main() {
    int n = read();

    vector<ll> x(n), p(n), c(n);
    rep(i, n) x[i] = read<ll>(), p[i] = read<ll>(), c[i] = read<ll>();

    auto P = p;
    rep(i, n-1) P[i+1] += P[i];
    vector<ll> Q(n);
    rep(i, n) Q[i] = p[i]*x[i];
    rep(i, n-1) Q[i+1] += Q[i];

    ll ans = 0;
    CHT cht;
    cht.add(0, 0);
    rep(i, n) {
        ans = cht.get(x[i]);
        ans += P[i]*x[i] - Q[i] + c[i];
        cht.add(-P[i], ans+Q[i]);
    }
    if (p[n-1] == 0) ans -= c[n-1];

    cout << ans << '\n';

    return 0;
}

0 评论

App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息