bzoj1492货币兑换Cash
题意:有A,B两种纪念券,最初由S元,有n天,每天有A,B的价值并可以以任意比例购买或卖出A,B两券,求最后能剩多少钱。
有一个点很明显,对于每一天,要么全买,要么全卖。
记f(i)为第i天最多能有多少钱,X[i]表示第i天最多能有多少A券,Y[i]为B券
则Y[j]=f[j]/(b[j]+a[j]*rate[j])
X[j]=Y[j]*rate[j]
f[i]=max(f[i-1],a[i]*X[j]+b[i]*Y[j])
Y[j]=-a[i]/b[i]*X[j]+f[i]/b[i]
然后斜率优化搞一搞,发现斜率不单调,可以用splay维护一下。
当然,还是CDQ大发好。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 using namespace std; 7 const double eps=1e-10; 8 struct node { 9 double a,b,k,x,y,rate; 10 int id; 11 bool operator < (const node &rhs) const { 12 return k>rhs.k; 13 } 14 }p[100005],q[100005]; 15 double f[100005]; 16 int sta[100005],n; 17 double getk(int g,int w) { 18 if (!w) return -1e10; 19 if (fabs(p[g].x-p[w].x)<eps) return 1e10; 20 return (p[g].y-p[w].y)/(p[g].x-p[w].x); 21 } 22 void solve(int l,int r) { 23 if (l>r) return; 24 if (l==r) { 25 f[l]=max(f[l],f[l-1]); 26 p[l].y=f[l]/(p[l].b+p[l].a*p[l].rate); 27 p[l].x=p[l].y*p[l].rate; 28 return; 29 } 30 int mid=(l+r) >> 1,j=l-1,k=mid; 31 for (int i=l;i<=r;i++) 32 if (p[i].id<=mid) q[++j]=p[i];else q[++k]=p[i]; 33 for (int i=l;i<=r;i++) p[i]=q[i]; 34 solve(l,mid); 35 int top=0,now=1; 36 for (int i=l;i<=mid;i++) { 37 while (top>1&&getk(sta[top-1],sta[top])<getk(sta[top],i)+eps) top--; 38 sta[++top]=i; 39 } 40 for (int i=mid+1;i<=r;i++) { 41 while (now<top&&p[i].k<getk(sta[now],sta[now+1])+eps) now++; 42 f[p[i].id]=max(f[p[i].id],p[i].a*p[sta[now]].x+p[i].b*p[sta[now]].y); 43 } 44 solve(mid+1,r); 45 j=l;k=mid+1; 46 for (int i=l;i<=r;i++) { 47 if (k>r||(j<=mid&&(p[j].x<p[k].x||(fabs(p[j].x-p[k].x)<eps&&p[j].y<p[k].y)))) q[i]=p[j++]; 48 else q[i]=p[k++]; 49 } 50 for (int i=l;i<=r;i++) p[i]=q[i]; 51 } 52 53 int main() 54 { 55 scanf("%d%lf",&n,&f[0]); 56 for (int i=1;i<=n;i++) { 57 scanf("%lf%lf%lf",&p[i].a,&p[i].b,&p[i].rate); 58 p[i].id=i;p[i].k=-p[i].a/p[i].b; 59 } 60 sort(p+1,p+n+1); 61 solve(1,n); 62 printf("%.3lf",f[n]); 63 return 0; 64 }