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
#include "iostream" #include "iomanip" #include "algorithm" using namespace std; constexpr int N = 1e6 + 10; #define int long long 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); } #define lson rt << 1, l, mid #define rson rt << 1 | 1, mid + 1, r #define y(p, i) (k[i] * tmp[p] + b[i]) 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; }
posted @   Steven1013  阅读(6)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开