您的位置:首页 > 其它

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

2018-01-14 20:20 483 查看

题目:

我是超链接

题解:

这题目有点眼熟啊。。。莫不是货币兑换?

那根据套路来一波dp,f[i]表示到第D[i]天卖掉所有机器得到的最多金钱,显然f[0]=c

f[i]=max(f[i−1],f[j]−P[j]+(D[i]−D[j]−1)∗G[j]+R[j])

列完方程我们可以知道,之所以这样设计是因为读入的D[i]影响的是前一群机器而不是这一个(因为还没开始用。)

f[i]=f[j]−P[j]+(D[i]−D[j]−1)∗G[j]+R[j]

f[j]−P[j]−(D[j]+1)∗G[j]+R[j]=−D[i]∗G[j]+f[i]

那就是斜率固定-D[i],使截距f[i]最大,把之前的看做一个点(G[j],f[j]-P[j]-(D[j]+1)*G[j]+R[j]),那就维护一个上凸壳用cdq分治求解

注意比较的时候不能光比较x,还要把y比上

INF要设的大一点= =

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
using namespace std;
const double INF=1e18;   ////
const int N=100005;
struct hh{int id;LL x,y,d,p,r,g,k;}Q
,jl
;
int stack
,n;
LL f
,d,c;
double getk(hh a,hh b)
{
if (a.x==b.x) return -INF;
return (double)(a.y-b.y)/(double)(a.x-b.x);
}
int cmpx(hh a,hh b){return a.x<b.x||(a.x==b.x&&a.y>b.y);} ////
void merge(int l,int r)
{
int mid=(l+r)>>1,t1=l,t2=mid+1;
for (int i=l;i<=r;i++)
if ((t1<=mid && cmpx(Q[t1],Q[t2])) || t2>r) jl[i]=Q[t1++];
else jl[i]=Q[t2++];
for (int i=l;i<=r;i++) Q[i]=jl[i];
}
void cdq(int l,int r)
{
if (l==r)
{
f[l]=max(f[l],f[l-1]);
Q[l].x=Q[l].g;
if (f[l]>=Q[l].p) Q[l].y=f[l]-Q[l].p-(LL)(Q[l].d+1)*Q[l].g+Q[l].r;
else Q[l].y=-INF;
return;
}
int mid=(l+r)>>1,t1=l,t2=mid+1;
for (int i=l;i<=r;i++)
if (Q[i].id<=mid) jl[t1++]=Q[i];
else jl[t2++]=Q[i];
for (int i=l;i<=r;i++) Q[i]=jl[i];
cdq(l,mid);
int top=0;
for (int i=l;i<=mid;i++)
if (Q[i].y!=-INF)
{
while (top>1 && getk(Q[i],Q[stack[top]])>=getk(Q[stack[top-1]],Q[stack[top]])) top--;
stack[++top]=i;
}
for (int i=mid+1;i<=r;i++)
{
while (top>1 && getk(Q[stack[top]],Q[stack[top-1]])<jl[i].k) top--;
int j=stack[top];
f[jl[i].id]=max(f[jl[i].id],Q[j].y-(LL)jl[i].k*Q[j].x);
}
cdq(mid+1,r); merge(l,r);
}
int cmpk(hh a,hh b){return a.k<b.k;}
int cmpd(hh a,hh b){return a.d<b.d;}
int main()
{
int id=0;scanf("%d%lld%lld",&n,&c,&d);
while (n&&c&&d)
{
memset(f,0,sizeof(f));f[1]=c;
for (int i=1;i<=n;i++) scanf("%lld%lld%lld%lld",&Q[i].d,&Q[i].p,&Q[i].r,&Q[i].g);
sort(Q+1,Q+n+1,cmpd);
for (int i=1;i<=n;i++) Q[i].id=i,Q[i].k=-Q[i].d;
Q[++n].d=d+1; Q
.k=-Q
.d; Q
.id=n;
sort(Q+1,Q+n+1,cmpk);
cdq(1,n);
printf("Case %d: %lld\n",++id,f
);
scanf("%d%lld%lld",&n,&c,&d);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: