[BZOJ1492] [NOI2007]货币兑换Cash 斜率优化+cdq/平衡树维护凸包

1492: [NOI2007]货币兑换Cash

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 5907  Solved: 2377
[Submit][Status][Discuss]

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 的变化分别为:

假定在第一天时,用户手中有 100元 人民币但是没有任何金券。用户可以执行以下的操作:

注意到,同一天内可以进行多次操作。小Y是一个很有经济头脑的员工,通过较长时间的运作和行情测算,他已经

知道了未来N天内的A券和B券的价值以及Rate。他还希望能够计算出来,如果开始时拥有S元钱,那么N天后最多能

够获得多少元钱。

Input

输入第一行两个正整数N、S,分别表示小Y能预知的天数以及初始时拥有的钱数。接下来N行,第K行三个实数AK、B

K、RateK,意义如题目中所述。对于100%的测试数据,满足:0<AK≤10;0<BK≤10;0<RateK≤100;MaxProfit≤1

0^9。

【提示】

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

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

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

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

Output

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

Sample Input

3 100

1 1 1

1 2 2

2 2 3

Sample Output

225.000

HINT

Source

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<algorithm>
 7 #define eps 1e-9
 8 #define maxn 120000
 9 #define inf 2147483647
10 using namespace std;
11 struct P {
12     double x,y;
13 }p[maxn],pp[maxn];
14 bool operator <(P t1,P t2){return (t1.x<t2.x+eps)||(fabs(t1.x-t2.x)<=eps&&t1.y<t2.y+eps);}
15 struct data {
16     double q,a,b,rate,k;
17     int pos;
18 }ask[maxn],askt[maxn];
19 int n;
20 double f[maxn];
21 bool cmp(data t1,data t2) {return t1.k<t2.k;}
22 double get(int i,int j) {
23     if(!i) return -inf;
24     if(!j) return inf;
25     if(fabs(p[i].x-p[j].x)<=eps) return -inf;
26     return (p[i].y-p[j].y)/(p[i].x-p[j].x);
27 }
28 int sta[maxn];
29 void cdq(int l,int r) {
30     if(l==r) {
31         f[l]=max(f[l-1],f[l]);
32         p[l].y=f[l]/(ask[l].a*ask[l].rate+ask[l].b);
33         p[l].x=p[l].y*ask[l].rate;
34         return;
35     }
36     int mid=l+r>>1,l1=l,l2=mid+1;
37     for(int i=l;i<=r;i++)
38         if(ask[i].pos<=mid) askt[l1++]=ask[i];
39         else askt[l2++]=ask[i];
40     for(int i=l;i<=r;i++) ask[i]=askt[i];
41     cdq(l,mid);
42     int top=0;
43     for(int i=l;i<=mid;i++) {
44         while(top>=2&&get(i,sta[top])+eps>get(sta[top],sta[top-1])) top--;
45         sta[++top]=i;
46     }
47     int j=1;
48     for(int i=r;i>=mid+1;i--) {
49         while(j<top&&ask[i].k<get(sta[j],sta[j+1])+eps) j++;
50         f[ask[i].pos]=max(f[ask[i].pos],p[sta[j]].x*ask[i].a+p[sta[j]].y*ask[i].b);
51     }
52     cdq(mid+1,r);
53     l1=l,l2=mid+1;
54     for(int i=l;i<=r;i++) {
55         if((p[l1]<p[l2]||l2>r)&&l1<=mid) pp[i]=p[l1++];
56         else pp[i]=p[l2++];
57     }
58     for(int i=l;i<=r;i++) p[i]=pp[i];
59 }
60 int main() {
61     scanf("%d%lf",&n,&f[0]);
62     for(int i=1;i<=n;i++) {
63         scanf("%lf%lf%lf",&ask[i].a,&ask[i].b,&ask[i].rate);
64         ask[i].k=-ask[i].a/ask[i].b;ask[i].pos=i;
65     }
66     sort(ask+1,ask+n+1,cmp);
67     cdq(1,n);
68     printf("%.3lf\n",f[n]);
69 }

原文地址:https://www.cnblogs.com/wls001/p/8550491.html

时间: 2024-10-09 01:05:21

[BZOJ1492] [NOI2007]货币兑换Cash 斜率优化+cdq/平衡树维护凸包的相关文章

[BZOJ1492][NOI2007]货币兑换Cash(斜率优化+CDQ分治)

1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 5838  Solved: 2345[Submit][Status][Discuss] Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金

【BZOJ1492】[NOI2007]货币兑换Cash 斜率优化+cdq分治

[BZOJ10492][NOI2007]货币兑换Cash Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动,两种金券都有自己当时的价值,即每一单位金券当天可以兑换的人民币数目.我们记录第 K 天中 A券 和 B券 的价值分别为 AK 和 BK(元/单位金券).为了方便顾客,金券交易所提供了一种非常方便的交易方式:比例交易

【BZOJ 1492】 [NOI2007]货币兑换Cash 斜率优化DP

先说一下斜率优化:这是一种经典的dp优化,是OI中利用数形结合的思想解决问题的典范,通常用于优化dp,有时候其他的一些决策优化也会用到,看待他的角度一般有两种,但均将决策看为二维坐标系上的点,并转化为维护凸壳,一种根据两点的斜率与某一常数的大小关系推断二者的优劣,一种将转移方程化为相关直线方程,通过取得最大(小)截距来求最优解.关于其实现方法上,当点的x坐标单调时,可依据比较常数是否单调选择单调队列或单调栈,而当其x坐标不单调时常常使用CDQ分治或平衡树来实现. 千万别用替罪羊来写动态凸壳!!!

bzoj1492[NOI2007]货币兑换Cash cdq分治+斜率优化dp

1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 5541  Solved: 2228[Submit][Status][Discuss] Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金

bzoj千题计划237:bzoj1492: [NOI2007]货币兑换Cash

http://www.lydsy.com/JudgeOnline/problem.php?id=1492 dp[i] 表示 第i天卖完的最大收益 朴素的dp: 枚举从哪一天买来的在第i天卖掉,或者是不操作 dp[i]=max(dp[i-1],X[j]*A[i]+Y[j]*B[i]) 其中X[j]表示在第j天能买多少A纪念券,Y[j]表示在第j天能买多少B纪念券 可列方程 X[j]*A[j]+Y[j]*B[j]=dp[j] 又因为 X[j]=Rate[j]*Y[j] 所以解出 Y[j]=dp[j]

cdq分治入门--BZOJ1492: [NOI2007]货币兑换Cash

n<=100000天,一开始有s块钱,每天股票A价格ai,B价格bi,每天可以做的事情:卖出股票:按A:B=RTi的比例买入股票.问最后的最大收益.股票可以为浮点数,答案保留三位. 用脚指头想想就知道是:某一天全部买进来,某一天全部卖出去,没有说买一半卖一半的. 那就可以dp了,f(i)表示前i天最大收益,,其中Xi表示用f(i)块钱在第i天能买多少A券,Yi表示f(i)块前第i天买多少B券,可以自己算,n方过不了. 现要找max(Ai*Xj+Bi*Yj),考虑两个状态j,k,j比k优时 整理得

BZOJ1492: [NOI2007]货币兑换Cash

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1492 f[i]=max(f[i-1],x[j]*a[i]+y[j]*b[i]) f[i]表示最大获利,x[j],y[j]分别表示第j天能够换到的最多的A,B券数量. 在斜率优化中如果每个状态给的斜率是单调的,凸包上的点x坐标,y坐标都是单调的..那上个单调队列就可以了.. 这题中给的斜率和凸包上的点x坐标都不是单调的... (因为不会写平衡树维护动态凸包所以写了cdq分治.. 其实...老老

bzoj1492: [NOI2007]货币兑换Cash(待更新)

1D1D动态规划问题.网上的大多都说有三类,然而我觉得吧,就是两类,一类利用单调性和斜率优化可以解决的,主要是因为能证明单调性(斜率与二元组的横坐标同时满足单调性,实际上很多时候都不用列二元组,你搞斜率优化的时候看得出来吧)那不单调就只能这样搞了. 暴力. /* O(n^2)暴力DP,f表示这天有多少人民币,转移时就转换成券来求 A表示A券价值,B表示B券价值,S表示这个券的数量 题意得:A*Sa+B*Sb=F,Sa/Sb=R (A*R+B)*Sb=F; Sb=F/(A*R+B); Sa=Sb*

【BZOJ-1492】货币兑换Cash DP + 斜率优化 + CDQ分治

1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 3396  Solved: 1434[Submit][Status][Discuss] Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金