BZOJ1492: [NOI2007]货币兑换Cash

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

f[i]=max(f[i-1],x[j]*a[i]+y[j]*b[i]) f[i]表示最大获利,x[j],y[j]分别表示第j天能够换到的最多的A,B券数量。

在斜率优化中如果每个状态给的斜率是单调的,凸包上的点x坐标,y坐标都是单调的。。那上个单调队列就可以了。。

这题中给的斜率和凸包上的点x坐标都不是单调的。。。

(因为不会写平衡树维护动态凸包所以写了cdq分治。。

其实。。。老老实实看论文比较好。。

我就口胡几句吧TAT。。 先插入的点对后面的点有贡献。。如果能够使得凸包上的点x,y坐标有序,询问的区间斜率是有序的。那就可以维护个栈啊什么的吧。。

于是先对斜率排序,按时间分成左右两个区间,左边区间暴力做出上凸包,右边区间询问。最后把两个区间按x,y合并起来(这样x,y坐标就有序辣)。。

#include<cstring>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<map>
#include<cmath>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define down(i,l,r) for (int i=l;i>=r;i--)
#define clr(x,y) memset(x,y,sizeof(x))
#define maxn 100500
#define inf int(1e9)
#define ll long long
#define eps 1e-9
using namespace std;
struct data{double k,a,b,x,y,r;int id;
}a[maxn],t[maxn];
int n,s[maxn];
double f[maxn];
int read(){
    int x=0,f=1; char ch=getchar();
    while (!isdigit(ch)){if (ch=='-') f=-1; ch=getchar();}
    while (isdigit(ch)){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}   
bool cmp(data a,data b){
    return a.k>b.k;
}
double getk(int A,int B)
{
    if(!B)return -1e20;
    if(fabs(a[A].x-a[B].x)<eps)return 1e20;
    return (a[B].y-a[A].y)/(a[B].x-a[A].x);
}
int cross(data a,data b,data c){
    double x1=b.x-a.x,y1=b.y-a.y,x2=c.x-a.x,y2=c.y-a.y;
    if (fabs(x1*y2-x2*y1)<eps) return 0;
    if (x1*y2-x2*y1>0) return 1;
    return -1;
}
void cdq(int l,int r){
    if (l==r){
        f[l]=max(f[l],f[l-1]);
        a[l].y=f[l]/(a[l].a*a[l].r+a[l].b);
        a[l].x=a[l].r*a[l].y;
        return;
    }
    int l1=l,l2=(l+r)/2+1,mid=(l+r)/2,j=1;
    rep(i,l,r) if (a[i].id<=mid) t[l1++]=a[i]; else t[l2++]=a[i];
    rep(i,l,r) a[i]=t[i];
    cdq(l,mid);
    int top=0;
    rep(i,l,mid){
        while (top>1&&cross(a[s[top-1]],a[s[top]],a[i])>=0) top--;
        s[++top]=i;
    }
    s[++top]=0;
    rep(i,mid+1,r) {
        while (j<top&&getk(s[j],s[j+1])+eps>a[i].k) j++;
        int now=a[i].id;
        f[now]=max(f[now],a[i].a*a[s[j]].x+a[i].b*a[s[j]].y);
    }   
    cdq(mid+1,r);
    l1=l,l2=mid+1;
    rep(i,l,r) if (l1<=mid&&(a[l1].x<a[l2].x||(fabs(a[l1].x-a[l2].x)<eps&&a[l1].y<a[l2].y)||l2>r ) ) t[i]=a[l1++]; else t[i]=a[l2++];
    rep(i,l,r) a[i]=t[i];
}
int main(){
    n=read(); scanf("%lf",&f[0]);
    rep(i,1,n){
        scanf("%lf%lf%lf",&a[i].a,&a[i].b,&a[i].r); a[i].id=i;
        a[i].k=-a[i].a/a[i].b;
    }
    sort(a+1,a+1+n,cmp);
    cdq(1,n);
    printf("%.3lf\n",f[n]);
    return 0;
}

 

你可能感兴趣的:(BZOJ1492: [NOI2007]货币兑换Cash)