[NOI 2007]货币兑换Cash

Description

题库链接

(按我的语文水平完全无 fa♂ 概括题意,找了 hahalidaxin 的题意简述...

有 $AB$ 两种货币,每天可以可以付 $IP_i$ 元,买到 $A$ 券和 $B$ 券,且 $A:B=Rate_i$ ,也可以卖掉 $OP_i%$ 的 $A$ 券和 $B$ 券,每天 $AB$ 价值为 $A_i$ 和 $B_i$ 。
开始有 $S$ 元, $n$ 天后手中不能有 $AB$ 券,给出 $A_i,B_i,Rate_i$ ,问最大获益。

$1\leq n\leq 100000$

Solution

首先基于一个贪心思想:必然存在一种最优的买卖方案满足:每次买进操作使用完所有的人民币;每次卖出操作卖出所有的金券。

所以说其实对于每一天,其能够获得的最多的 $A,B$ 券个数是已知的,假设第 $i$ 天获得的最多的 $A$ 券为 $f$ , $i$ 天之前能够得到最多的钱为 $s$ 。那么有 $$fA_i+\frac{fB_i}{rate_i}=s\Rightarrow f=\frac{rate_is}{rate_iA_i+B_i}$$

那么容易得到 $O(n^2)$ 的 $DP$ 。可以获得 $60pts$ 。

考虑优化。还是由刚才的思想。

我们不妨记 $f_i$ 表示第 $i$ 天最大的收益。 注意,此处 $DP$ 数组的含义发生了变化

记第 $i$ 天得到的最多的 $A$ 券为 $x_i$ , $B$ 券为 $y_i$ 。显然 $x_i=rate_iy_i$ ,有 $$f_i=\max_{0\leq j<i} A_ix_j+B_iy_j$$

将上述式子变为斜距式: $$y=-\frac{A_i}{B_i}x+\frac{f_i}{B_i}$$

显然只要截距越大, $f_i$ 越大。

现在对于每个 $i$ 前的每天都可以抽象成一个点对 $(x,y)$ 。显然只要使第 $i$ 天的“这条直线”切于前面 $0\sim i-1$ 天的点对组成的上凸包时即可得到 ${f_i}_{max}$ 。

用 $CDQ$ 维护即可。

Code

60pts

//It is made by Awson on 2018.3.20
#include <bits/stdc++.h>
#define LL long long
#define dob complex<double>
#define Abs(a) ((a) < 0 ? (-(a)) : (a))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
#define writeln(x) (write(x), putchar('\n'))
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int N = 100000;
void read(int &x) {
    char ch; bool flag = 0;
    for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
    for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
    x *= 1-2*flag;
}
void print(int x) {if (x > 9) print(x/10); putchar(x%10+48); }
void write(int x) {if (x < 0) putchar('-'); print(Abs(x)); }

int n, s;
double f[N+5], a[N+5], b[N+5], rate[N+5], ans;

void work() {
    read(n), read(s);
    for (int i = 1; i <= n; i++) scanf("%lf%lf%lf", &a[i], &b[i], &rate[i]);
    ans = s;
    for (int i = 1; i <= n; i++) {
    for (int j = 1; j < i; j++)
        ans = max(ans, f[j]*a[i]+f[j]/rate[j]*b[i]);
    f[i] = ans*rate[i]/(a[i]*rate[i]+b[i]);
    }
    printf("%.3lf\n", ans);
}
int main() {work(); return 0; }

100pts

//It is made by Awson on 2018.3.21
#include <bits/stdc++.h>
#define LL long long
#define dob complex<double>
#define Abs(a) ((a) < 0 ? (-(a)) : (a))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
#define writeln(x) (write(x), putchar('\n'))
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int N = 100000;
const double eps = 1e-7, INF = 2e33;
void read(int &x) {
    char ch; bool flag = 0;
    for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
    for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
    x *= 1-2*flag;
}
void print(int x) {if (x > 9) print(x/10); putchar(x%10+48); }
void write(int x) {if (x < 0) putchar('-'); print(Abs(x)); }

int n, s, S[N+5], top;
struct tt {double x, y, k; int id; }ob[N+5];
double f[N+5], a[N+5], b[N+5], rate[N+5];
bool compk(const tt &a, const tt &b) {return a.k > b.k; }
bool compid(const tt &a, const tt &b) {return a.id < b.id; }
bool comppos(const tt &a, const tt &b) {return a.x == b.x ? a.y < b.y : a.x < b.x; }

double k(const int &a, const int &b) {
    if (ob[a].x-ob[b].x < eps) return -INF;
    return (ob[a].y-ob[b].y)/(ob[a].x-ob[b].x);
}
void solve(int l, int r) {
    if (l == r) {
    f[l] = max(f[l], f[l-1]);
    ob[l].y = f[l]/(a[l]*rate[l]+b[l]);
    ob[l].x = rate[l]*ob[l].y;
    return;
    }
    int mid = (l+r)>>1;
    sort(ob+l, ob+r+1, compid); solve(l, mid); top = 0;
    for (int i = l; i <= mid; i++) {
    while (top >= 2 && k(i, S[top]) > k(S[top], S[top-1])) --top;
    S[++top] = i;
    }
    sort(ob+mid+1, ob+r+1, compk); int loc = 1;
    for (int i = mid+1; i <= r; i++) {
    while (loc < top && ob[i].k < k(S[loc+1], S[loc])) ++loc;
    f[ob[i].id] = max(f[ob[i].id], a[ob[i].id]*ob[S[loc]].x+b[ob[i].id]*ob[S[loc]].y);
    }
    solve(mid+1, r); sort(ob+l, ob+r+1, comppos);
}
void work() {
    read(n), read(s); f[0] = s;
    for (int i = 1; i <= n; i++) {
    scanf("%lf%lf%lf", &a[i], &b[i], &rate[i]);
    ob[i].id = i, ob[i].k = -a[i]/b[i];
    }
    solve(1, n); printf("%.3lf\n", f[n]);
}
int main() {work(); return 0; }
posted @ 2018-03-21 19:07  NaVi_Awson  阅读(340)  评论(0编辑  收藏  举报