[BZOJ3963][WF2011]MachineWorks(斜率优化dp+cdq分治)

来源:互联网 发布:雪人翻译软件下载 编辑:程序博客网 时间:2024/05/18 03:54

题目描述

传送门

题解

首先考虑如何暴力dp
肯定是先按照D(i)排序对吧
令f(i)表示在第D(i)天卖掉手里有的机器所能得到的最大收入
那么有一个很显然的dp方程:f(i)=max{f(i-1),max{f(j)-P(j)+G(j)*(D(i)-D(j)-1)+R(j)}}(1<=j<=i-1)
只考虑后半部分,实际上就变成了f(i)=max{f(j)-P(j)+G(j)*(D(i)-D(j)-1)+R(j)}(1<=j<=i-1)
将这个式子变一下形式:f(i)=f(j)-P(j)+G(j)*D(i)-G(j)*D(j)-G(j)+R(j)->令y(j)=f(j)-P(j)-G(j)*D(j)-G(j)+R(j),x(j)=G(j)->f(i)=D(i)*x(j)+y(j)
我们发现这个式子是可以斜率优化的,也就是y(j)=-D(i)*x(j)+f(i);这样就可以看成是一条直线,斜率为-D(i),截距为f(i),现在要选出一个点使截距最大
斜率不满足单调性T_T;不过容易知道这个点一定在一个上凸壳上,那么用splay维护一个上凸壳就行了
用cdq分治的写法更加方便

代码

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define N 100005#define LL long longconst double inf=1e18;int Case,n;long double C,D;struct data{    long double d,p,r,g,k,x,y;    int id;    bool flag;}q[N],a[N],b[N];int stack[N];long double f[N];long double read(){    int x=0;char ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();    return (long double)x;}void clear(){    memset(f,0,sizeof(f));    memset(stack,0,sizeof(stack));    for (int i=1;i<=n+1;++i)    {        q[i].d=q[i].p=q[i].r=q[i].g=0,q[i].id=0,q[i].flag=0,q[i].k=q[i].x=q[i].y=0;        a[i].d=a[i].p=a[i].r=a[i].g=0,a[i].id=0,a[i].flag=0,a[i].k=a[i].x=a[i].y=0;        b[i].d=b[i].p=b[i].r=b[i].g=0,b[i].id=0,b[i].flag=0,b[i].k=b[i].x=b[i].y=0;    }}int cmpd(data a,data b){    return a.d<b.d;}int cmpx(data a,data b){    return a.x<b.x||(a.x==b.x&&a.y>b.y);}int cmpk(data a,data b){    return a.k>b.k;}double getk(data a,data b){    double ax=a.x,ay=a.y,bx=b.x,by=b.y;    if (ax==bx) return -inf;    return (ay-by)/(ax-bx);}void cdq(int l,int r){    int mid=(l+r)>>1;    if (l==r)    {        f[l]=max(f[l],f[l-1]);        if (f[l]>=q[l].p)        {            q[l].flag=1;            q[l].x=q[l].g;            q[l].y=f[l]-q[l].p-q[l].g*q[l].d-q[l].g+q[l].r;        }           return;    }    cdq(l,mid);    int acnt=0,bcnt=0;    for (int i=l;i<=mid;++i) a[++acnt]=q[i];    for (int i=mid+1;i<=r;++i) b[++bcnt]=q[i];    sort(a+1,a+acnt+1,cmpx);sort(b+1,b+bcnt+1,cmpk);    int top=0;    for (int i=1;i<=acnt;++i)        if (a[i].flag)        {            while (top>1&&getk(a[i],a[stack[top]])>=getk(a[stack[top]],a[stack[top-1]]))                --top;            stack[++top]=i;        }    int now=1;    for (int i=1;i<=bcnt;++i)    {        while (now<top&&getk(a[stack[now]],a[stack[now+1]])>=b[i].k)            ++now;        int t=stack[now];        f[b[i].id]=max(f[b[i].id],(LL)a[t].x*b[i].d+(LL)a[t].y);    }    cdq(mid+1,r);}int main(){    while (~scanf("%d",&n))    {        if (!n) break;        C=read();D=read();        clear();        for (int i=1;i<=n;++i)        {            q[i].d=read();q[i].p=read();q[i].r=read();q[i].g=read();            q[i].k=-q[i].d;        }        sort(q+1,q+n+1,cmpd);        q[++n].d=D+1,q[n].p=0,q[n].r=0,q[n].g=0,q[n].k=-q[n].d;        for (int i=1;i<=n;++i) q[i].id=i;        f[1]=C;        cdq(1,n);        printf("Case %d: %lld\n",++Case,(long long)f[n]);    }}
0 0
原创粉丝点击