P4027 [NOI2007] 货币兑换
[NOI2007] 货币兑换
算法
动态规划, 斜率优化, 李超线段树.
思路
注意到题末有两行小字:
必然存在一种最优的买卖方案满足:
每次买进操作使用完所有的人民币, 每次卖出操作卖出所有的金券.
考虑动态规划, 令 \(f_i\) 表示到第 \(i\) 天时最多拥有 \(f_i\) 元钱, 钦定 \(\displaystyle x_i = \frac{f_i \cdot Rate_i}{A_i \cdot Rate_i + B_i}, y_i = \frac{f_i}{A_i \cdot Rate_i + B_i}\), 表示第 \(i\) 天用 \(f_i\) 元买入的 A, B 券数量.
若第 \(i\) 天不买不卖, 那么 \(f_i = f_{i - 1}\);
若第 \(i\) 天要卖, 那么我们枚举买入时间 \(j\), 就有 \(\displaystyle f_i = \max_{j < i} A_i x_j + B_i y_j\), 将 \(B_i\) 提出来: \(\displaystyle f_i = \max_{j < i} B_i(x_j \frac{A_i}{B_i} + y_j)\).
这样问题就转化成: 每次插入斜率为 \(x_j\), 截距为 \(y_j\) 的直线, 求 \(x = \frac{A_i}{B_i}\) 时的最大值, 用李超线段树维护即可.
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
using namespace std;
constexpr int N = 1e6 + 10;
int n, s;
double A[N], B[N], R[N];
double x[N], tmp[N];
void init() {
cin >> n >> s;
for (int i = 1; i <= n; ++i)
cin >> A[i] >> B[i] >> R[i], x[i] = tmp[i] = 1.0 * A[i] / B[i];
sort(tmp + 1, tmp + n + 1);
}
class Segment_Tree {
private:
double k[N], b[N];
int s[N << 2];
public:
void add(int i, double f) {
k[i] = f * (1.0 * R[i]) / (1.0 * A[i] * R[i] + B[i]);
b[i] = f / (1.0 * A[i] * R[i] + B[i]);
}
void update(int rt, int l, int r, int t) {
if (l == r) {
if (y(l, t) > y(l, s[rt])) s[rt] = t;
return;
}
int mid = (l + r) >> 1;
if (y(mid, t) > y(mid, s[rt])) swap(s[rt], t);
if (y(l, t) > y(l, s[rt])) update(lson, t);
else update(rson, t);
}
double query(int rt, int l, int r, int u) {
if (l == r) return y(u, s[rt]);
int mid = (l + r) >> 1;
return max(y(u, s[rt]), u <= mid ? query(lson, u) : query(rson, u));
}
} st;
void calculate() {
double ans = s;
for (int i = 1; i <= n; ++i) {
ans = max(ans, 1.0 * B[i] * st.query(1, 1, n, lower_bound(tmp, tmp + n + 1, x[i]) - tmp));
st.add(i, ans), st.update(1, 1, n, i);
}
cout << fixed << setprecision(3) << ans << '\n';
}
void solve() {
init();
calculate();
}
signed main() {
cin.tie(nullptr)->sync_with_stdio(false);
solve();
return 0;
}
分类:
题目总结 / 2025. 1~3月
, 题目总结
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步