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; }