【BZOJ】1492: [NOI2007]货币兑换Cash-斜率优化&cdq分治

传送门:bzoj1492


题解

斜率优化+cdq分治


代码

#include<bits/stdc++.h>
using namespace std;
typedef double db;
const int N=1e5+10;
const db eps=1e-10,inf=2e9;

int n,stk[N],top;db f[N];

struct Q{
  db a,b,rt,k;int id;
  inline void ini(){
    scanf("%lf%lf%lf",&a,&b,&rt);
    k=-a/b;
  }
  bool operator <(const Q&ky)const{
     return k<ky.k;
  }
}t[N],res[N];
struct P{
   db x,y;
   P(db x_=0,db y_=0):x(x_),y(y_){};
   bool operator <(const P&ky)const{
       return (x<ky.x+eps || (fabs(x-ky.x)<eps && y<ky.y+eps));
   }
   P operator -(const P&ky)const{return P(x-ky.x,y-ky.y);}
   db operator ^(const P&ky)const{return x*ky.y-y*ky.x;}
}p[N],rep[N];

inline bool onl(P A,P B,P C){return ((B-A)^(C-B))+eps>0;}
inline db slp(P A,P B)
{
    if(fabs(A.x-B.x)<=eps) return inf;
    return (B.y-A.y)/(B.x-A.x);
}

void solve(int l,int r)
{
    if(l==r){
        f[l]=max(f[l],f[l-1]);
        p[l].y=f[l]/(t[l].a*t[l].rt+t[l].b);
        p[l].x=p[l].y*t[l].rt;
        return;
    }
    int k,mid=(l+r)>>1,i=l,j=mid+1;
    for(k=l;k<=r;++k){
        if(t[k].id<=mid) res[i++]=t[k];
        else res[j++]=t[k];
    }
    for(k=l;k<=r;++k) t[k]=res[k];
    solve(l,mid);
    top=0;
    for(k=l;k<=mid;++k){
        for(;top>1 && onl(p[stk[top-1]],p[stk[top]],p[k]);--top);
        stk[++top]=k;
    }
    for(i=1,k=r;k>mid;--k){
        for(;i<top && slp(p[stk[i]],p[stk[i+1]])+eps>t[k].k;++i);
        f[t[k].id]=max(f[t[k].id],t[k].a*p[stk[i]].x+t[k].b*p[stk[i]].y);
    }
    solve(mid+1,r);
    i=l;j=mid+1;
    for(k=l;k<=r;++k){
        if((j>r)||(i<=mid && p[i]<p[j])) rep[k]=p[i++];
        else rep[k]=p[j++];
    }
    for(k=l;k<=r;++k) p[k]=rep[k];
}

int main(){
    int i;
    scanf("%d%lf",&n,&f[0]);
    for(i=1;i<=n;++i) t[i].ini(),t[i].id=i;
    sort(t+1,t+n+1);
    solve(1,n);
    printf("%.3lf",f[n]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值