• 洛谷 P4027 [NOI2007]货币兑换 解题报告


    P4027 [NOI2007]货币兑换

    题目描述

    (Y) 最近在一家金券交易所工作。该金券交易所只发行交易两种金券:(A) 纪念券(以下简称 (A) 券)和 (B) 纪念券(以下简称 (B) 券)。每个持有金券的顾客都有一个自己的帐户。金券的数目可以是一个实数。

    每天随着市场的起伏波动,两种金券都有自己当时的价值,即每一单位金券当天可以兑换的人民币数目。我们记录第 (K) 天中 (A) 券和 (B) 券的价值分别为 (A_K)(B_K) (元/单位金券)。

    为了方便顾客,金券交易所提供了一种非常方便的交易方式:比例交易法。

    比例交易法分为两个方面:

    a) 卖出金券:顾客提供一个([0,100])内的实数 (OP) 作为卖出比例,其意义为:将 (OP\%)(A) 券和 (OP\%)(B) 券以当时的价值兑换为人民币;

    b) 买入金券:顾客支付 (IP) 元人民币,交易所将会兑换给用户总价值为 (IP) 的金券,并且,满足提供给顾客的 (A) 券和 (B) 券的比例在第 (K) 天恰好为 (Rate_K)

    例如,假定接下来 (3) 天内的 (A_k)(B_k)(Rate_K) 的变化分别为:

    时间 (A_k) (B_k) (Rate_k)
    第一天 1 1 1
    第二天 1 2 2
    第三天 2 2 3

    假定在第一天时,用户手中有 (100) 元人民币但是没有任何金券。

    用户可以执行以下的操作:

    时间 用户操作 人民币(元) A券的数量 B券的数量
    开户 (100) (0) (0)
    第一天 买入 (100) (0) (50) (50)
    第二天 卖出 (50\%) (75) (25) (25)
    第二天 买入(60) (15) (55) (40)
    第三天 卖出 (100\%) (205) (0) $0

    注意到,同一天内可以进行多次操作。

    (Y) 是一个很有经济头脑的员工,通过较长时间的运作和行情测算,他已经知道了未来 (N) 天内的 (A) 券和 (B) 券的价值以及 (Rate)。他还希望能够计算出来,如果开始时拥有 (S) 元钱,那么 (N) 天后最多能够获得多少元钱。

    输入输出格式

    输入格式:

    第一行两个正整数 (N)(S),分别表示小 (Y) 能预知的天数以及初始时拥有的钱数。

    接下来 (N) 行,第 (K) 行三个实数 (A_K)(B_K)(Rate_K) ,意义如题目中所述。

    输出格式:

    只有一个实数 (MaxProfit),表示第 (N) 天的操作结束时能够获得的最大的金钱数目。答案保留 (3) 位小数。

    说明

    本题没有部分分,你的程序的输出只有和标准答案相差不超过(0.001)时,才能获得该测试点的满分,否则不得分。

    测试数据设计使得精度误差不会超过 (10^{-7})

    对于(40\%)的测试数据,满足 (N le 10)

    对于(60\%)的测试数据,满足 (N le 1 000)

    对于(100\%)的测试数据,满足 (N le 100 000)

    对于(100\%)的测试数据,满足:

    (0 < A_K le 10)

    (0 < B_K le 10)

    (0 < Rate_Kle 100)

    (MaxProfit le 10^9)

    提示:

    输入文件可能很大,请采用快速的读入方式。

    必然存在一种最优的买卖方案满足:

    每次买进操作使用完所有的人民币;

    每次卖出操作卖出所有的金券。


    居然有提示,虽然还是比较显而易见的..

    太久没写斜率优化式子都没转过去..

    (dp_i)代表第(i)天(还未决定买不买)的最大拥有金钱数量

    [dp_i=max(dp_j,frac{dp_jRate_j}{Rate_jA_j+B_j} imes A_i+frac{dp_j}{Rate_jA_j+B_j} imes B_i) ]

    然后把和(i)与和(j)有关的项分开表示

    [dp_i=a_jA_i+b_jB_i ]

    转换一下

    [a_j=-b_jfrac{B_i}{A_i}+frac{dp_i}{A_i} ]

    这就很标准的斜率优化了叭,但发现这些东西没啥单调性,于是不能简单的单调队列了。

    可以拿平衡树动态维护,不过CDQ的做法会更好写常数也更小。

    说一下CDQ大概的实现

    左边的按(x)坐标排序以后(O(n))弄出个斜率递减的凸包,右边直接按斜率从大到小排序,然后像归并那样边合并边做就好了。这样应该写起来是最简单的,尝试写二分但发现有点麻烦。

    注意要还原右边。


    Code:

    #include <cstdio>
    #include <algorithm>
    using std::max;
    const int N=1e5+10;
    const double eps=1e-7;
    const double inf=1e10;
    struct node
    {
        double a,b,c,k,ans;int id;
    }q[N];
    int s[N],tot,n;
    double ans;
    std::pair <double,double > poi[N];
    bool cmp1(node n1,node n2){return n1.k>n2.k;}
    bool cmp2(node n1,node n2){return n1.id<n2.id;}
    double slope(int i,int j)
    {
        double x=poi[i].first,y=poi[i].second,xx=poi[j].first,yy=poi[j].second;
        if(xx-x<eps) return inf;
        return (yy-y)/(xx-x);
    }
    void CDQ(int l,int r)
    {
        if(l==r){q[l].ans=max(ans,q[l].ans),ans=max(ans,q[l].ans);return;}
        int mid=l+r>>1;
        CDQ(l,mid);
        for(int i=l;i<=mid;i++)
            poi[i]=std::make_pair(-q[i].ans/(q[i].a*q[i].c+q[i].b),q[i].ans/(q[i].a*q[i].c+q[i].b)*q[i].c);
        std::sort(poi+l,poi+mid+1);
        tot=0;
        for(int i=l;i<=mid;i++)
        {
            while(tot>1&&slope(s[tot-1],s[tot])+eps<slope((s[tot]),i)) --tot;
            s[++tot]=i;
        }
        std::sort(q+mid+1,q+r+1,cmp1);
        int lp=1;
        for(int i=mid+1;i<=r;i++)
        {
            while(lp<tot&&q[i].k+eps<slope(s[lp],s[lp+1])) ++lp;
            q[i].ans=max(q[i].ans,-poi[s[lp]].first*q[i].b+poi[s[lp]].second*q[i].a);
        }
        std::sort(q+mid+1,q+r+1,cmp2);
        CDQ(mid+1,r);
    }
    int main()
    {
        scanf("%d%lf",&n,&ans);
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf",&q[i].a,&q[i].b,&q[i].c);
            q[i].id=i,q[i].k=q[i].b/q[i].a;
        }
        CDQ(1,n);
        printf("%.3lf
    ",ans);
        return 0;
    }
    

    2018.11.28

  • 相关阅读:
    华为云发送邮件
    activiti act_re_model 分析
    tengine upstream
    zuul压力测试与调优
    idea 快捷键
    kubernetes helm
    编写高质量代码–改善python程序的建议(二)
    编写高质量代码--改善python程序的建议(一)
    总结OpenvSwitch的调试经验
    提高SDN控制器拓扑发现性能
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10030612.html
Copyright © 2020-2023  润新知