您的位置:首页 > 其它

BZOJ 3963: [WF2011]MachineWorks [CDQ分治 斜率优化DP]

2017-02-25 15:46 405 查看
传送门

当然了WF的题uva hdu上也有

你的公司获得了一个厂房N天的使用权和一笔启动资金,你打算在这N天里租借机器进行生产来获得收益。
可以租借的机器有M台。每台机器有四个参数D,P,R,G。你可以在第D天花费P的费用(当然,前提是你有至少P元)租借这台机器,从第D+1天起,操作机器将为你产生每天G的收益。在你不再需要机器时,可以将机器卖掉,一次性获得R的收益。
厂房里只能停留一台机器。
不能在购买和卖出机器的那天操作机器,但是可以在同一天卖掉一台机器再买入一台。
在第N+1天,你必须卖掉手上的机器。
求第N+1天后能获得的最大资金。

$DP-naive$相当好写

$f[i]$为第$i$天卖掉后最大收益

$f[i]=max{f[i-1],f[j]-P_j+R_j+G_j*(D_i-D_j-1)}$

然后变成点斜式

$f_i=A_j+G_j*D_i$

$A_j=-D_i*G_j+f_i$

$(G_j,A_j)$是点,斜率$D_i$正好按时间排序后单调(也就是说本题时间和斜率是一个东西,不用像$cash$那样按斜率排序然后分治里要先按时间分成两块)

然后$CDQ$分治维护上凸壳就行啦

fuxey那里学到可以用计算几何那一套来避免精度问题,太棒啦!

然后我花了两节课调试修改,主要是因为:

本题的$y$需要加上$f$啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊

我一开始不考虑$f$结果狂$WA$,然后发现$fuxey$求凸包额外排序了才想到应该加上$f$

但是复杂度加一个$log$好别扭啊

于是我把$f$放到归并的比较里,又狂$WA$

然后发现$f$的下标需要用按时间排序后的下标,又去保存了一个$id$........

还有一点,要保证$f[j]>P_j$才能买

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int N=1e5+5,INF=1e9;
inline int read(){
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
struct Vector{
ll x,y;
Vector(ll a=0,ll b=0):x(a),y(b){}
};
Vector operator -(Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);}
typedef Vector Point;
double Cross(Vector a,Vector b){return (double)a.x*b.y-(double)a.y*b.x;}

int n,D;
struct Machine{
int d,p,r,g;
ll x,y;
int id;
void ini(){
d=read();p=read();r=read();g=read();
x=g;y=-p+r-(ll)d*g-g;
}
}a
,t
;

inline bool cmpDay(const Machine &a,const Machine &b){return a.d<b.d;}
ll f
;
inline bool cmp(int i,int j){return a[i].x==a[j].x ? a[i].y+f[a[i].id]<a[j].y+f[a[j].id] : a[i].x<a[j].x;}
Point p
,ch
;
inline ll line(ll k,Point &p){return k*p.x+p.y;}
void CDQ(int l,int r){
if(l==r){f[l]=max(f[l],f[l-1]);return;}
int mid=(l+r)>>1;
CDQ(l,mid);
int n=0,m=0;
for(int i=l;i<=mid;i++) if(f[a[i].id]>=a[i].p) //!!!!!
p[++n]=Point(a[i].x,a[i].y+f[a[i].id]);
for(int i=1;i<=n;i++){
while(m>1&&Cross(ch[m]-ch[m-1],p[i]-ch[m-1])>=0) m--;
ch[++m]=p[i];
}
int j=1;
for(int i=mid+1;i<=r;i++){
while(j<m&&line(a[i].d,ch[j+1])>=line(a[i].d,ch[j])) j++;
if(j<=m) f[i]=max(f[i],line(a[i].d,ch[j]));
}
CDQ(mid+1,r);

int p1=l,p2=mid+1;
for(int i=l;i<=r;i++){
if(p2>r||(p1<=mid&&cmp(p1,p2))) t[i]=a[p1++];
else t[i]=a[p2++];
}
for(int i=l;i<=r;i++) a[i]=t[i];
}
int main(){
freopen("in","r",stdin);
int cas=0;
while(scanf("%d%lld%d",&n,&f[0],&D)!=EOF){
if(n==0&&f[0]==0&&D==0) break;
for(int i=1;i<=n;i++) a[i].ini();
a[++n].d=D+1;
sort(a+1,a+1+n,cmpDay);
for(int i=1;i<=n;i++) a[i].id=i,f[i]=0;
CDQ(1,n);
printf("Case %d: %lld\n",++cas,f
);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: