zoukankan      html  css  js  c++  java
  • 【NOI2007】货币兑换

    
    

    P1472 - 【NOI2007】货币兑换

    
    

    Description

    小 Y最近在一家金券交易所工作。该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和B纪念券(以下简称B券)。每个持有金券的顾客都有一个自己的 帐户。金券的数目可以是一个实数。每天随着市场的起伏波动,两种金券都有自己当时的价值,即每一单位金券当天可以兑换的人民币数目。我们记录第K天中A券 和B券的价值分别为AK和BK(元/单位金券)。
    为了方便顾客,金券交易所提供了一种非常方便的交易方式:比例交易法。
    比例交易法分为两个方面:
    a)卖出金券:顾客提供一个[0,100]内的实数OP作为卖出比例,其意义为:将OP%的A券和OP%的B券以当时的价值兑换为人民币;
    b)买入金券:顾客支付IP元人民币,交易所将会兑换给用户总价值为IP的金券,并且,满足提供给顾客的A券和B券的比例在第K天恰好为RateK;
    例如,假定接下来3天内的Ak、Bk、RateK的变化分别为:
    Pic
    注意到,同一天内可以进行多次操作。
    小Y是一个很有经济头脑的员工,通过较长时间的运作和行情测算,他已经知道了未来N天内的A券和B券的价值以及Rate。他还希望能够计算出来,如果开始时拥有S元钱,那么N天后最多能够获得多少元钱。

    
    

    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

    样例说明:

    Pic

    数据范围:
    测试数据设计使得精度误差不会超过10^-7。
    对于40%的测试数据,满足N ≤10;
    对于60%的测试数据,满足N ≤1 000;
    对于100%的测试数据,满足N ≤100 000;
    对于100%的测试数据,满足:
    0 < Ak ≤ 10
    0 < Bk≤ 10
    0 < Ratek ≤ 100
    MaxProfit ≤ 10^9
    提示
    输入文件可能很大,请采用快速的读入方式。
    必然存在一种最优的买卖方案满足: 每次买进操作使用完所有的人民币;每次卖出操作卖出所有的金券。
    【评分方法】
    本题没有部分分,你的程序的输出只有和标准答案相差不超过0.001时,才能获得该测试点的满分,否则不得分。



    题目中有一句:
    必然存在一种最优的买卖方案满足: 每次买进操作使用完所有的人民币;每次卖出操作卖出所有的金券。
    所以可以设Y[i]表示第i天的B能买的B卷数量,则X[i]=Rate[i]
    f[i]=A[i]*X[j]+B[i]*Y[j]
    所以f[i]=max(f[i],A[i]*(Rate[j]*f[j])/(A[j]*Rate[j]+B[j])
    +B[i]*f[j]/(A[j]*Rate[j]+B[j]));
    然后就有60分了。
    AC做法:斜率优化。
    f[i]=A[i]*X[j]+B[i]*Y[j].
    f[i]=A[i]*(X[j]+B[i]/A[i]*Y[j])
    可以看出A[i]B[i]都是常数。
    所以就是求B[i]/A[i]*Y[j]+X[j]的最大值。kx+b,斜率优化。
    但这个Y[j]并不是单调的啊,所以单调队列不能用了。
    看数据范围,显然这道题的正解并不是O(n)的。
    所以就有一种神奇的东西,可以nlogn搞完,叫做CDQ分治...好像这道题就是这个算法的发明题。
    按照斜率优化线的做法,要在双端队列中维护斜率递减的直线,好像维护的这东西叫做半平面交。
    所以就先按照时间排序,从中间二分,保证左边的时间都小于右边的时间,然后用左边更新右边。
    把左边按照斜率升序排序,维护一个半平面交。
    把右边按照x坐标升序排序,然后再线性扫一遍,因为这时已经满足单调性了。
    还有一堆的细节要处理。
     1     #include <algorithm>
     2     #include <iostream>
     3     #include <cstdlib>
     4     #include <cstring>
     5     #include <cstdio>
     6     #include <cmath>
     7     #define maxn 100010
     8     using namespace std;
     9     double A[maxn],B[maxn],Rate[maxn],f[maxn];
    10     struct data{
    11       double x,k,b;
    12       int id;
    13     }g[maxn],p[maxn],q[maxn];
    14     bool cmp(const data &a,const data &b){
    15       return a.x<b.x;
    16     }
    17     bool cmpp(const data &a,const data &b){
    18       return a.k<b.k;
    19     }
    20     void CDQ(int l,int r){
    21       if(l==r) return;
    22       int mid=(l+r)>>1,l1=l,l2=mid+1,head=1,tail=0;
    23       double MAX=0;
    24       for(int i=l;i<=r;i++){
    25         if(g[i].id<=mid) p[l1++]=g[i];
    26         else p[l2++]=g[i];
    27       }
    28       for(int i=l;i<=r;i++) g[i]=p[i];
    29       CDQ(l,mid);
    30       sort(g+l,g+mid+1,cmpp);
    31       for(int i=l;i<=mid;i++){
    32         while(head<tail && (g[i].b-q[tail].b)*(-q[tail].k+q[tail-1].k)<=(q[tail].b-q[tail-1].b)*(-g[i].k+q[tail].k))
    33           tail--;
    34         q[++tail]=g[i],MAX=max(MAX,f[g[i].id]);
    35       }
    36       sort(g+mid+1,g+r+1,cmp);
    37       for(int i=mid+1;i<=r;i++){
    38         while(head<tail&&q[head].k*g[i].x+q[head].b<=q[head+1].k*g[i].x+q[head+1].b)
    39           head++;
    40         f[g[i].id]=max(f[g[i].id],max(MAX,A[g[i].id]*(q[head].k*g[i].x+q[head].b)));
    41         g[i].k=f[g[i].id]/(A[g[i].id]*Rate[g[i].id]+B[g[i].id]),g[i].b=g[i].k*Rate[g[i].id];
    42       }
    43       CDQ(mid+1,r);
    44     }
    45     int main()
    46     {
    47       //freopen("!.in","r",stdin);
    48       //freopen("!.out","w",stdout);
    49       int n;
    50       scanf("%d%lf",&n,&f[0]);
    51       for(int i=1;i<=n;i++){
    52         scanf("%lf%lf%lf",&A[i],&B[i],&Rate[i]);
    53         f[i]=f[0],g[i].id=i,g[i].x=B[i]/A[i];
    54         g[i].k=f[i]/(A[i]*Rate[i]+B[i]);
    55         g[i].b=Rate[i]*f[i]/(A[i]*Rate[i]+B[i]);
    56       }
    57       CDQ(1,n);
    58       /*for(int i=2;i<=n;i++){
    59         for(int j=1;j<i;j++)
    60         f[i]=max(f[i],A[i]*(Rate[j]*f[j])/(A[j]*Rate[j]+B[j])+B[i]*f[j]/(A[j]*Rate[j]+B[j]));
    61         f[i]=max(f[i],f[i-1]);
    62       }*/
    63       printf("%.3lf",f[n]);
    64       return 0;
    65     }
    
    
    
    
    
  • 相关阅读:
    Win10 VirtualBox 安装 OpenWrt/LEDE
    在华为云、腾讯云服务器中部署 Hadoop 集群
    记一次部署Hadoop后遭受kthreaddi挖矿病毒
    四种基本编程命名法
    词云图制作
    在Ubuntu18.04lts下安装NS2(含nam)
    二叉树的建立与遍历
    国内pip镜像
    java高斯消元模板
    图的3种储存方式
  • 原文地址:https://www.cnblogs.com/pantakill/p/6708427.html
Copyright © 2011-2022 走看看