\(\mathcal{Description}\)

  Link.

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

\(\mathcal{Solution}\)

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

\[f(i)=\max_{f(j)\ge p_j}\{f(j)-p_j+r_j+g_j(d_i-d_j-1)\}.
\]

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

\[\begin{aligned}
&f(u)-p_u+r_u+g_u(d_i-d_u-1)>f(v)-p_v+r_v+g_v(d_i-d_v-1) \\
\Longleftrightarrow~~~~&[f(u)-p_u+r_u-g_u(d_u+1)]-[f(v)-p_v-r_v-g_v(d_v+1)]>(g_v-g_u)d_i \\
\Longleftrightarrow~~~~&\frac{h(u)-h(v)}{g_u-g_v}<-d_i~~~~(g_u<g_v).
\end{aligned}
\]

  很遗憾我们需要 \(g_u<g_v\) 控制符号,所以无法保证此时斜率 \(-d_i\) 的单调性,所以得写一发 CDQ 或者李超树。复杂度都是 \(\mathcal O(n\log n)\)。

\(\mathcal{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;
}

最新文章

  1. 分享篇——我的Java学习路线
  2. Redis实现唯一计数的3种方法分享
  3. HDU 1402 fft 模板题
  4. 【Pro ASP.NET MVC 3 Framework】.学习笔记.6.SportsStore:导航
  5. messagepcak 资料
  6. translate函数说明
  7. php 大流量网站访问
  8. Simple Addition
  9. ORACLE处理用户进程大剖析[阅读]
  10. Python3:几行代码实现阶乘
  11. phpstorm----------phpstorm设置自动更新的ssh信息如何修改--后续增加如何设置自动更新
  12. Apache Druid架构原理与应用场景
  13. React 学习(六) ---- 父子组件之间的通信
  14. PHP中json数组与对象的问题
  15. OGG文件获取创建日期
  16. springboot深入学习(三)-----docker
  17. Flask-SQLAlchemy 无法创建Sqlite 数据库???
  18. find查找时排除目录及文件
  19. python并行计算(持续更新)
  20. Freemarker-2.3.22 Demo - No02_绑定单个参数

热门文章

  1. wordpress搭建网站更改域名后打开网页排版显示错乱解决办法
  2. Samba服务器搭建与配置
  3. Linux上天之路(四)之Linux界面介绍
  4. Linux上天之路(十七)之Shell编程二
  5. Java日期格式化带来的年份不正确
  6. phar反序列化
  7. leetcode刷题目录
  8. webstorm 配置git代码项目管理工具
  9. Javascript对象数据类型(键值对)的创建和使用方法
  10. 【刷题-LeetCode】275. H-Index II