Solution -「WF2011」「BZOJ #3963」MachineWorks
阿新 • • 發佈:2021-11-11
\(\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)\)
注意同一天多次買賣機器顯然不優,所以 \(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\)
\(\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; }