zoukankan      html  css  js  c++  java
  • [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) ,问最大获益。

    (1leq nleq 100000)

    Solution

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

    所以说其实对于每一天,其能够获得的最多的 (A,B) 券个数是已知的,假设第 (i) 天获得的最多的 (A) 券为 (f)(i) 天之前能够得到最多的钱为 (s) 。那么有 [fA_i+frac{fB_i}{rate_i}=sRightarrow 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_{0leq 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) 天的“这条直线”切于前面 (0sim 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('
    '))
    #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
    ", 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('
    '))
    #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
    ", f[n]);
    }
    int main() {work(); return 0; }
  • 相关阅读:
    Google Earth 使用的经纬度格式及转换
    ADO.NET Entity Framework 一个简单数据绑定例子
    Oracle 异常 ORA01861: literal does not match format string(字符串格式不匹配)
    备份和还原 甲方 Oracle 数据库 问题一大堆
    使用 xsd.exe 命令工具 将 xsd架构 生成 类文件
    简单的源代码统计工具(统计源代码行数、工数、成本、质量指标统计)
    Google KML 起步教程笔记(二)高级 KML 文档与MIME 类型
    SQL Server 2008 中的空间数据存储
    PowerCmd 很好用的命令行工具,也许大家早就知道。
    Google Earth 本地地图缓存文件路径和KML文件路径
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8618293.html
Copyright © 2011-2022 走看看