BZOJ 1492 货币兑换Cash

http://www.lydsy.com/JudgeOnline/problem.php?id=1492

思路:

问题转变为维护一个凸包,每次转移都找凸包上的点,并更新凸壳

可以用splay维护,或者说,可以用cdq分治去维护,左半边构成的凸壳对右半边答案的影响~

 

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
const double eps=1e-9;
double f[500005];
struct node{
    double a,b,rate,x,y,k;
    int id;
}p[500005],tmp[500005];
int n,stack[500005];
int read(){
    int t=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
    return t*f;
}
bool cmp(node a,node b){
    return a.k>b.k;
}
double getk(int a,int b){
    if (!b) return -1e20;
    if (fabs(p[a].x-p[b].x)<eps) return 1e20;
    return (p[b].y-p[a].y)/(p[b].x-p[a].x);
}
void cdq(int l,int r){
    if (l==r){
        f[l]=std::max(f[l],f[l-1]);
        p[l].y=f[l]/(p[l].a*p[l].rate+p[l].b);
        p[l].x=p[l].rate*p[l].y;
        return;
    }
    int mid=(l+r)>>1;
    int l1=l-1,l2=mid;
    for (int i=l;i<=r;i++)
        if (p[i].id<=mid)
            tmp[++l1]=p[i];
        else
            tmp[++l2]=p[i];
    for (int i=l;i<=r;i++)
        p[i]=tmp[i];
    cdq(l,mid);
    int top=0;
    for (int i=l;i<=mid;i++){
         while (top>1&&getk(stack[top-1],stack[top])<getk(stack[top-1],i)+eps) top--;
             stack[++top]=i;
    }
    stack[++top]=0;int j=1;
    for (int i=mid+1;i<=r;i++){
         while (j<top&&getk(stack[j],stack[j+1])+eps>p[i].k) j++;
         f[p[i].id]=std::max(f[p[i].id],p[stack[j]].x*p[i].a+p[stack[j]].y*p[i].b);
    }
    cdq(mid+1,r);
    l1=l,l2=mid+1;
    for (int i=l;i<=r;i++){
        if ((((p[l1].x<p[l2].x)||(fabs(p[l1].x-p[l2].x)<eps&&p[l1].y<p[l2].y))||l2>r)&&l1<=mid) tmp[i]=p[l1++];
        else tmp[i]=p[l2++];
    }
    for (int i=l;i<=r;i++)
         p[i]=tmp[i];
}
int main(){
    scanf("%d",&n);scanf("%lf",&f[0]);
    for (int i=1;i<=n;i++){
        scanf("%lf%lf%lf",&p[i].a,&p[i].b,&p[i].rate);
        p[i].k=-p[i].a/p[i].b;
        p[i].id=i;
    }
    std::sort(p+1,p+1+n,cmp);
    cdq(1,n);
    printf("%.3lf",f[n]);
}

 Splay代码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
const double eps=1e-8;
int fa[2000005],ch[2000005][2];
double lk[2000005],rk[2000005];
double x[200005],y[200005],f[200005],rate[200005],a[200005],b[200005];
int n,root;
int read(){
    int t=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
    return t*f;
}
void rotate(int x,int &rt){
    int y=fa[x],z=fa[y],l,r;
    if (ch[y][0]==x) l=0;else l=1;r=l^1;
    if (y!=rt){
        if (ch[z][0]==y) ch[z][0]=x;
            else ch[z][1]=x;
    }else rt=x;
    fa[x]=z;fa[y]=x;fa[ch[x][r]]=y;
    ch[y][l]=ch[x][r];ch[x][r]=y;
}
void splay(int x,int &rt){
    while (x!=rt){
        int y=fa[x],z=fa[y];
        if (y!=rt){
           if ((ch[y][0]==x)^(ch[z][0]==y)) rotate(x,rt);
           else rotate(y,rt);
        }
        rotate(x,rt);
    }
}
void insert(int &k,int Fa,int id){
     if (!k){
        k=id;
        fa[k]=Fa;
        return; 
     }
     if (x[k]+eps>=x[id]) insert(ch[k][0],k,id);
         else insert(ch[k][1],k,id);
}
double getk(int i,int j){
     if (fabs(x[i]-x[j])<eps) return -1e9;
     else return (y[i]-y[j])/(x[i]-x[j]);
}
int pre(int rt){
     int k=ch[rt][0];int tmp=k;
     while (k){
            if (lk[k]+eps>=getk(k,rt)) tmp=k,k=ch[k][1];
            else k=ch[k][0];
     }
     return tmp;
}
int suc(int rt){
     int k=ch[rt][1];int tmp=k;
     while (k){
            if (rk[k]<=eps+getk(k,rt)) tmp=k,k=ch[k][0];
            else k=ch[k][1];
     }
     return tmp;
}
void updata(int k){
     splay(k,root);
     if (ch[k][0]){
        int left=pre(root);
        splay(left,ch[k][0]);ch[left][1]=0;
        lk[k]=rk[left]=getk(k,left); 
     }else lk[k]=1e9;
     if (ch[k][1]){
        int right=suc(root);
        splay(right,ch[k][1]);ch[right][0]=0;
        lk[right]=rk[k]=getk(k,right);
     }else rk[k]=-1e9;
     if (lk[k]<=rk[k]+eps){
        root=ch[k][0];
        ch[root][1]=ch[k][1];
        fa[ch[k][1]]=root;
        fa[root]=0;
        rk[root]=lk[ch[k][1]]=getk(root,ch[k][1]);
     }
}
int find(int k,double slop){
    if (!k) return 0;
    if (lk[k]+eps>=slop&&slop+eps>=rk[k]){
        return k;
    }
    if (slop+eps>lk[k]) return find(ch[k][0],slop);
    else return find(ch[k][1],slop);
}
int main(){
    n=read();scanf("%lf",&f[0]);
    for (int i=1;i<=n;i++){
        scanf("%lf%lf%lf",&a[i],&b[i],&rate[i]);
    }
    for (int i=1;i<=n;i++){
        int j=find(root,-a[i]/b[i]);
        f[i]=std::max(f[i-1],x[j]*a[i]+b[i]*y[j]);
        y[i]=f[i]/(a[i]*rate[i]+b[i]);
        x[i]=y[i]*rate[i];
        insert(root,0,i);
        updata(i);
    }
    printf("%.3f\n",f[n]);
}

 

posted @ 2016-07-13 10:37  GFY  阅读(203)  评论(0编辑  收藏  举报