Live2D

Solution -「WF2011」「BZOJ #3963」MachineWorks

Description

  Link.

  给定你初始拥有的钱数 C 以及 N 台机器的属性,第 i 台有属性 (di,pi,ri,gi),分别是出售时间、售价、转卖价、单日工作收益。机器在买入或转卖当天不提供收益,且你同一时刻最多拥有一台机器,在 (D+1) 天时必须转卖拥有的机器。求第 (D+1) 天你拥有的最大钱数。n105

Solution

  比较自然的想法时依时间顺序 DP,所以先将机器按时间排序。令 f(i) 表示在 di 时刻,卖掉手里的机器后拥有的最大钱数,添加一台虚拟机器 (D+1,0,0,0) 用于收集答案。考虑转移:

f(i)=maxf(j)pj{f(j)pj+rj+gj(didj1)}.

注意同一天多次买卖机器显然不优,所以 gj 的系数不需要对 0max。这个一看就是斜优的样子,研究 f(u),f(v)i 的转移:

f(u)pu+ru+gu(didu1)>f(v)pv+rv+gv(didv1)    [f(u)pu+rugu(du+1)][f(v)pvrvgv(dv+1)]>(gvgu)di    h(u)h(v)gugv<di    (gu<gv).

  很遗憾我们需要 gu<gv 控制符号,所以无法保证此时斜率 di 的单调性,所以得写一发 CDQ 或者李超树。复杂度都是 O(nlogn)

Code

/*+Rainybunny+*/

#include <bits/stdc++.h>

#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i)

typedef long long LL;
typedef long double LD;

inline void chkmax(LL& u, const LL v) { u < v && (u = v); }

const int MAXN = 1e5;
int N, C, D;
LL f[MAXN + 5], g[MAXN + 5];
struct Machine { int day, buy, sel, pro; } mch[MAXN + 5];

inline LD slope(const int u, const int v) {
    return LD(g[u] - g[v]) / (mch[u].pro - mch[v].pro);
}

inline std::vector<int> solve(const int l, const int r) {
    if (l == r) {
        chkmax(f[l], C);
        g[l] = f[l] - mch[l].buy + mch[l].sel
          - mch[l].pro * (mch[l].day + 1ll);
        // printf("f(%d)=%lld\n", l, f[l]);
        return f[l] >= mch[l].buy ? std::vector<int>{ l } : std::vector<int>{};
    }

    int mid = l + r >> 1;
    auto&& cvxL(solve(l, mid));
    for (int i = 0, j = mid + 1; j <= r; ++j) {
        while (i + 1 < int(cvxL.size())
          && slope(cvxL[i], cvxL[i + 1]) >= -mch[j].day) ++i;
        if (i < int(cvxL.size())) { // maybe cvxL is empty.
            int p = cvxL[i];
            chkmax(f[j], f[p] - mch[p].buy + mch[p].sel
              + mch[p].pro * (mch[j].day - mch[p].day - 1ll));
        }
    }
    auto&& cvxR(solve(mid + 1, r));

    std::vector<int> ret;
    auto push = [&](const int u) { // maintain the up-convex.
        while (ret.size() > 1 && slope(ret[ret.size() - 2], ret.back())
          <= slope(ret.back(), u)) ret.pop_back();
        ret.push_back(u);
    };

    for (size_t i = 0, j = 0; i < cvxL.size() || j < cvxR.size();) {
        if (i < cvxL.size() && j < cvxR.size()
          && mch[cvxL[i]].pro == mch[cvxR[j]].pro) {
            ++(g[cvxL[i]] < g[cvxR[j]] ? i : j); // pass the smaller one.
        } else if (j == cvxR.size()
          || (i < cvxL.size() && mch[cvxL[i]].pro < mch[cvxR[j]].pro)) {
            push(cvxL[i++]);
        } else {
            push(cvxR[j++]);
        }
    }
    return ret;
}

int main() {
    std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);

    while (std::cin >> N >> C >> D && N | C | D) {
        rep (i, 1, N) {
            std::cin >> mch[i].day >> mch[i].buy >> mch[i].sel >> mch[i].pro;
        }
        std::sort(mch + 1, mch + N + 1,
          [](const Machine& u, const Machine& v) { return u.day < v.day; });
        mch[++N] = { D + 1, 0, 0, 0 };
        rep (i, 1, N) f[i] = g[i] = 0;

        solve(1, N);
        static int cas = 0;
        std::cout << "Case " << ++cas << ": " << f[N] << '\n';
    }

    return 0;
}

posted @   Rainybunny  阅读(43)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示