Description
Input
Output
Sample Input
6 12 1 3
1 9 1 2
3 2 1 2
8 20 5 4
4 11 7 4
2 10 9 1
0 0 0
Sample Output
分析:
将所有的机器按照从小到大排序
假设你买到了一台好的机器,在下一个机器进来之前,你肯定是一直运转下去的
f[i]
f
[
i
]
表示在
d[i]
d
[
i
]
卖掉手里的机器后的最大收益,枚举买入新机器的时间
j
j
其中
f[j]>=p[i]
f
[
j
]
>=
p
[
i
]
复杂度
O(n2)
O
(
n
2
)
,,想办法优化
仔细观察一下状态注意方程,实际上是这样的形式:
f[i]=max(f[i−1],f[j]+w(i,j))
f
[
i
]
=
m
a
x
(
f
[
i
−
1
]
,
f
[
j
]
+
w
(
i
,
j
)
)
可以考虑用斜率优化:
但是
g
g
不单调,不能直接用单调队列,不过容易知道这个点一定在一个上凸壳上,考虑CDQ分治
对于一个区间,先更新
[l,mid]
[
l
,
m
i
d
]
然后对左边这部分的区间的点集, 进行排序,形成上凸壳
在更新右边区间的时候,由于斜率是递减的,所以我们只需要扫一遍这个图形即可完成所有右边区间值的更新
然后就这样递归着去更新,完成CDQ分治
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 100033
#define eps 1e-9
#define ll long long
using namespace std;
const double inf=1e19;
int n,C,D,top,s[N];
ll f[N];
struct data{
ll d,r,p,g,id;
}a[N],po[N];
struct point{
ll x,y; bool pd;
bool operator <(const point &b) const {
return x<b.x||(x==b.x&&y>b.y);
}
}p[N],q[N];
int cmp(data a,data b)
{
return a.d<b.d;
}
double get(int i,int j) {
if (p[i].x-p[j].x==0) return -inf;
return (double)(p[i].y-p[j].y)/(double)(p[i].x-p[j].x);
}
void CDQ(int l,int r)
{
if (l==r) {
f[l]=max(C-a[l].p,f[l]); p[l].pd=0;
if (f[l]<0) f[l]=-1,p[l].pd=1;
p[l].x=a[l].g;
p[l].y=f[l]-a[l].d*a[l].g-a[l].g+a[l].r;
return;
}
int mid=(l+r)/2;
int t1=l; int t2=mid+1;
for (int i=l;i<=r;i++)
if (a[i].id<=mid) po[t1++]=a[i];
else po[t2++]=a[i];
for (int i=l;i<=r;i++) a[i]=po[i];
CDQ(l,mid);
int top=0;
for (int i=l;i<=mid;i++) {
if (p[i].pd) continue;
while (top>1&&get(i,s[top])+eps>get(s[top],s[top-1])) top--;
s[++top]=i;
}
if (top) {
int j=1;
for (int i=mid+1;i<=r;i++) {
while (j<top&&get(s[j],s[j+1])>-a[i].d)
j++;
int k=s[j];
f[a[i].id]=max(f[a[i].id],p[k].y+p[k].x*a[i].d-a[i].p);
}
}
CDQ(mid+1,r);
t1=l,t2=mid+1;
for (int i=l;i<=r;i++)
if ((p[t1]<p[t2]||t2>r)&&t1<=mid) q[i]=p[t1++];
else q[i]=p[t2++];
for (int i=l;i<=r;i++)
p[i]=q[i];
}
int main()
{
int T=0;
while (scanf("%d%d%d",&n,&C,&D)!=EOF&&n+C+D) {
T++;
for (int i=1;i<=n;i++) scanf("%lld%lld%lld%lld",&a[i].d,&a[i].p,&a[i].r,&a[i].g);
n++; a[n].d=D+1; a[n].p=0; a[n].r=0; a[n].g=0;
for (int i=1;i<=n;i++) f[i]=-1;
sort(a+1,a+1+n,cmp);
for (int i=1;i<=n;i++) a[i].id=i;
CDQ(1,n);
printf("Case %d: %lld\n",T,f[n]);
}
}