[BZOJ1492][NOI2007]货币兑换Cash

来源:互联网 发布:60数据库 编辑:程序博客网 时间:2024/04/29 22:58

[NOI2007]货币兑换Cash

Description
这里写图片描述

Input
第一行两个正整数N、S,分别表示小Y 能预知的天数以及初始时拥有的钱数。 接下来N 行,第K 行三个实数AK、BK、RateK,意义如题目中所述
Output
只有一个实数MaxProfit,表示第N 天的操作结束时能够获得的最大的金钱 数目。答案保留3 位小数。
Sample Input
3 100
1 1 1
1 2 2
2 2 3
Sample Output
225.000
HINT

这里写图片描述

测试数据设计使得精度误差不会超过10-7。
对于40%的测试数据,满足N ≤ 10;
对于60%的测试数据,满足N ≤ 1 000;
对于100%的测试数据,满足N ≤ 100 000;

Solution:
首先我们列出dp方程
dp[i]=max{f[j]B[j]+A[j]Rate[j](Rate[j]A[i]+B[i])}
dp[0]=S
这是一个典型的1D/1Ddp
具体推导如下
y[j]=f[j]B[j]+A[j]Rate[j],x[j]=y[j]Rate[j]

dp[i]=max{x[j]A[i]+y[j]B[i]}
这是典型的斜率优化形式,斜率和横坐标都不单调,因此我们需要splay
【吐槽:bzoj的数据太弱了,你们可以看到我的maintain函数其实只考虑了把新插进来的决策左边拉成凸壳,右边拉成凸壳,而如果我的新决策点在原凸壳里的话这样做是不对的,应该先判断点是否在凸壳内部的,我也不知道为什么这样就对了,大概是新点都在壳外面吧 = =

Code

#include <bits/stdc++.h>using namespace std;#define rep(i, l, r) for (int i = (l); i <= (r); i++)#define per(i, r, l) for (int i = (r); i >= (l); i--)#define MS(_) memset(_, 0, sizeof(_))#define PB push_back#define MP make_pair#define debug(...) fprintf(stderr, __VA_ARGS__)typedef long long ll;template<typename T> inline void read(T &x){    x = 0; T f = 1; char ch = getchar();    while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}    while (isdigit(ch))  {x = x * 10 + ch - '0'; ch = getchar();}    x *= f;}const double INF = 1e9;const double eps = 1e-9;const int N = 111111;int n;double x[N], y[N], dp[N], a[N], b[N], rate[N], k[2][N];//Geometryinline double calk(int a, int b){    if (abs(x[a]-x[b])<eps) return -INF;    return (y[a]-y[b])/(x[a]-x[b]); }inline bool gt(double a, double b) {return a-b > eps;}inline bool ge(double a, double b) {return a-b >= eps;}inline bool le(double a, double b) {return a-b <= eps;}inline bool check(double a, double b, int d){ return d ? ge(a, b) : le(a, b); }//Splaystruct Node{    Node *p, *ch[2]; int num;    inline int d(){return this == p->ch[1]; }    inline void sc(Node *_c, int _d) {ch[_d] = _c; if (_c) _c->p = this;}}*root, mem[N], *pos[N], *s[N]; int top;inline void init_memory(){REP(i, N) s[i] = mem+i; top = N;}inline void build(){init_memory(); root = 0;}inline Node *new_node() {return s[--top];}inline Node *new_node(int v){    Node *ret = new_node();    ret->num = v; ret->ch[0] = ret->ch[1] = ret->p = 0;    return ret;}inline void rot(Node *t){    Node *p = t->p; int d = t->d();    p->sc(t->ch[!d], d);     if (p->p) p->p->sc(t, p->d()); else t->p = 0;     t->sc(p, !d);     if (p == root) root = t;}inline void splay(Node *t, Node *fa = 0){    for (; t->p != fa; ){        if (t->p->p == fa) rot(t);        else t->d() == t->p->d() ? (rot(t->p), rot(t)) : (rot(t), (rot(t)));    }}inline int find(double nk){    Node *rt = root;    while (rt){        if (ge(k[0][rt->num], nk) && ge(nk, k[1][rt->num])) return rt->num;        rt = rt->ch[!gt(nk, k[0][rt->num])];    }    return 0;}inline void insert(Node *fa, Node *&rt, int num){    if (!rt) {pos[num] = rt = new_node(num); rt->p = fa; return;}    if (le(x[num], x[rt->num])) insert(rt, rt->ch[0], num);    else insert(rt, rt->ch[1], num);}inline Node *fix(int d){ Node *p, *res;    for (res = p = root->ch[d]; p;){        bool _d = check(calk(p->num, root->num), k[d][p->num], d);        if (_d){res = p; p = p->ch[!d];} else p = p->ch[d];    }    return res;}inline void maintain(int num){    Node *rt = pos[num]; splay(pos[num]);    rep(i, 0, 1)         if (rt->ch[i]){         Node *p = fix(i);        k[!i][p->num] = k[i][num] = calk(p->num, num);        splay(p, root); p->ch[!i] = 0;    }    if (!rt->ch[0]) k[0][num] = INF;    if (!rt->ch[1]) k[1][num] = -INF;}int main(){    read(n); scanf("%lf", &dp[0]); build();    rep(i, 1, n) scanf("%lf%lf%lf", &a[i], &b[i], &rate[i]);    rep(i, 1, n){        int p = find(-a[i]/b[i]);        dp[i] = max(dp[i-1], x[p]*a[i]+y[p]*b[i]);        y[i] = dp[i] / (a[i] * rate[i] + b[i]);        x[i] = y[i] * rate[i];         insert(0, root, i);        maintain(i);    }    printf("%.3lf\n",dp[n]);    return 0;}
0 0
原创粉丝点击