BZOJ_1492_[NOI2007]货币兑换Cash_CDQ分治+斜率优化
2018-06-20 09:47
459 查看
BZOJ_1492_[NOI2007]货币兑换Cash_CDQ分治+斜率优化
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 的变化分别为:![](https://www.lydsy.com/JudgeOnline/upload/201604/dd(1).png)
![](https://www.lydsy.com/JudgeOnline/upload/201604/dd(2).png)
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 1001 1 1
1 2 2
2 2 3
Sample Output
225.000HINT
首先贪心的想,每天的操作只有三种可能,什么也不干,全部买入和全部卖出。
设x[i]为第i天能获得A卷的数量,y[i]为第i天能获得B卷的数量。
y[i]=f[i]/(rate[i]*A[i]+B[i]),x[i]=y[i]*rate[i]。
那么f[i]=max(f[i-1],x[j]*A[i]+y[j]*B[i]),其中我们需要找到一个已经确定F值得j来转移这个过程。
F[i]=X[j]*A[i]+Y[j]*B[i]
F[i]/A[i]=Y[j]*(B[i]/A[i])+X[j]。
把Y[j]当做斜率。那么我们会发现不仅Y[j]不单调,每次切的横坐标(B[i]/A[i])也不单调。
这时候我们使用CDQ分治。
本题的思想:对左边进行处理,处理左边对右边的影响(F的转移),再对右边进行处理。
先按(B[i]/A[i])排序,然后每步再按斜率归并上去。
也就是说我们到了一个局面,满足左边的斜率单调,右边每次切的横坐标单调。
这个就很好办了,对左边单调栈求凸包,然后维护一个指针扫一遍凸包。
正确性:所有能更新F[i]的F[j]在更新F[i]之前都已经更新完毕了,同时F[i]被1~i-1中的每个F[j]都更新到了。
代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long ll; typedef double f2; #define N 100050 #define eps 1e-6 f2 xx ,yy ,f ,A ,B ,rate ,K ,pos ; int n,t ,tmp ,S ; #define Y(i,j) (K[j]*pos[i]+xx[j]) bool cmp(int x,int y) {return pos[x]<pos[y];} bool judge(int p1,int p2,int p3) { return (yy[p2]-yy[p3])*(xx[p1]-xx[p2])<=(yy[p1]-yy[p2])*(xx[p2]-xx[p3]); } void solve(int l,int r) { if(l==r) { f[l]=max(f[l],f[l-1]); yy[l]=f[l]/(rate[l]*A[l]+B[l]); xx[l]=yy[l]*rate[l]; K[l]=yy[l]; return ; } int mid=(l+r)>>1; int i,j=l,k=mid+1; for(i=l;i<=r;i++) { if(t[i]<=mid) tmp[j++]=t[i]; else tmp[k++]=t[i]; } for(i=l;i<=r;i++) t[i]=tmp[i]; solve(l,mid); int top=0; for(i=l;i<=mid;i++) { while(top>1&&judge(S[top-1],S[top],t[i])) top--; S[++top]=t[i]; } for(j=1,i=mid+1;i<=r;i++) { while(j<top&&Y(t[i],S[j+1])>=Y(t[i],S[j])) j++; f[t[i]]=max(f[t[i]],Y(t[i],S[j])*A[t[i]]); } solve(mid+1,r); i=j=l,k=mid+1; while(j<=mid&&k<=r) { if(K[t[j]]<=K[t[k]]) tmp[i++]=t[j++]; else tmp[i++]=t[k++]; } while(j<=mid) tmp[i++]=t[j++]; while(k<=r) tmp[i++]=t[k++]; for(i=l;i<=r;i++) t[i]=tmp[i]; } int main() { scanf("%d%lf",&n,&f[0]); int i,j; for(i=1;i<=n;i++) { scanf("%lf%lf%lf",&A[i],&B[i],&rate[i]); t[i]=i; pos[i]=B[i]/A[i]; } sort(t+1,t+n+1,cmp); solve(1,n); printf("%.3f\n",f ); }
相关文章推荐
- [BZOJ 1492][NOI2007]货币兑换Cash:CDQ分治|DP斜率优化
- [DP 斜率优化 CDQ分治||动态维护凸包] BZOJ 1492 [NOI2007]货币兑换Cash
- [BZOJ1492][NOI2007][CDQ分治][斜率优化][DP]货币兑换Cash
- [BZOJ1492][NOI2007]货币兑换Cash && CDQ分治+斜率优化
- [bzoj1492][cdq分治][斜率优化][NOI2007]货币兑换Cash
- [BZOJ1492][NOI2007]货币兑换Cash(斜率优化dp+splay|cdq分治维护凸包)
- 【BZOJ1492】[NOI2007]货币兑换Cash 斜率优化+cdq分治
- bzoj [NOI2007]货币兑换Cash (cdq分治+斜率优化 )
- BZOJ1492:[NOI2007]货币兑换Cash (CDQ分治+斜率优化DP/平衡树维护凸壳)
- [BZOJ1492][NOI2007][斜率优化][动态凸包][DP][分治]货币兑换cash
- NOI 2007 货币兑换Cash (bzoj 1492) - 斜率优化 - 动态规划 - CDQ分治
- 【bzoj1492】【NOI2007】【货币兑换】【斜率优化+cdq分治】
- BZOJ_P1492 [NOI2007]货币兑换Cash(CDQ分治+斜率优化)
- BZOJ 1492 货币兑换Cash(CDQ分治+斜率优化dp)
- [BZOJ1492]-[NOI2007]货币兑换Cash-斜率优化+CDQ
- BZOJ 1492: [NOI2007]货币兑换Cash [CDQ分治 斜率优化DP]
- 斜率优化(CDQ分治,Splay平衡树):BZOJ 1492: [NOI2007]货币兑换Cash
- bzoj1492 [NOI2007]货币兑换Cash【cdq分治】
- [BZOJ1492][NOI2007]货币兑换Cash(斜率优化dp+cdq分治)
- BZOJ1492:[NOI2007]货币兑换 (CDQ分治+斜率优化DP | splay动态维护凸包)