[bzoj 1492][NOI2007]货币兑换Cash

传送门

Solution

一道很早以前做过的题,突然想补篇博客……

方程什么的就不展现了。

反正斜率优化的题都挺好写的。

斜率优化的核心是:

\[\frac{Y_j-Y_k}{X_j-X_k}\leq W_i \]

可以把每个决策\(j\)用两个数\(X_j\),\(Y_j\)来表示,然后如果\(X_j\)是个单增的呢,直接用单调栈就能维护凸壳(因为求凸壳的时候就要\(x-y\)排序一波啊),其实,我们不如说是在维护一个斜率的单调队列,所以如果\(W_i\)和斜率的单调性相同,就可以直接用单调队列找决策点啦。

\(W_i\)没有单调性的话,就只能二分找决策点了。

比较头疼的是要是\(X_i\)没有单调性的话,我们就需要维护一个可以在中间加点的凸壳,平衡树即可。

而cdq分治的思想就是分治区间,只考虑前面的决策对后面的询问的影响,而顺序是不需要考虑的,所以直接对前面的决策\(x-y\)排序求凸壳,对后面的询问按照\(W_i\)排序,这样一来,就又可以直接用单调队列找决策点啦。


Code 

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
#define inf 0x7fffffff
#define MN 120000
#define sign(a) (((a)>-eps)-((a)<eps))
#define eps 1e-8
int n;
struct day{double A,B,rate;}a[MN];
double ans[MN],f[MN],g[MN];
int hd,tl,q[MN],krk[MN],rk[MN];
inline bool cmp(int x,int y){
    return f[x]<f[y]||(sign(f[x]-f[y])==0&&g[x]<g[y]);
}
inline double calc(int x,int y){
    if(sign(f[x]-f[y])==0) return (g[x]-g[y])*inf;
    return (g[x]-g[y])/(f[x]-f[y]);
}
inline bool cmpk(int x,int y){
    return sign((-a[x].A/a[x].B)-(-a[y].A/a[y].B))>0;
}
void solve_cdq(int l,int r){
    if(l==r){g[l]=f[l]/a[l].rate;return;}
    register int i,mid=(l+r)>>1;
    solve_cdq(l,mid);
    for(i=mid+1;i<=r;i++) rk[i]=i;sort(rk+l,rk+mid+1,cmp);
    for(i=mid+1;i<=r;i++) krk[i]=i;sort(krk+mid+1,krk+r+1,cmpk);
    tl=0,hd=1;
    for(i=l;i<=mid;i++){while(tl>1&&calc(q[tl-1],q[tl])<calc(q[tl],rk[i])) --tl;q[++tl]=rk[i];}
    for(i=mid+1;i<=r;i++){
        while(hd<tl&&sign(calc(q[hd],q[hd+1])-(-a[krk[i]].A/a[krk[i]].B))>=0)++hd;
        ans[krk[i]]=max(ans[krk[i]],f[q[hd]]*a[krk[i]].A+g[q[hd]]*a[krk[i]].B);
    }
    for(i=mid+1;i<=r;++i)
        ans[i]=max(ans[i],ans[i-1]),f[i]=ans[i]*a[i].rate/(a[i].A*a[i].rate+a[i].B);
    solve_cdq(mid+1,r);
}
int main(){
    register int i;
    n=read();scanf("%lf",&ans[1]);
    for(i=1;i<=n;i++) scanf("%lf%lf%lf",&a[i].A,&a[i].B,&a[i].rate),rk[i]=i;
    f[1]=ans[1]*a[1].rate/(a[1].A*a[1].rate+a[1].B);
    solve_cdq(1,n);
    printf("%.3f\n",ans[n]);
}


Blog来自PaperCloud,未经允许,请勿转载,TKS!

posted @ 2019-01-08 22:20  PaperCloud  阅读(166)  评论(0编辑  收藏  举报