3963: [WF2011]MachineWorks

3963: [WF2011]MachineWorks

Time Limit: 30 Sec   Memory Limit: 256 MB
Submit: 93   Solved: 28
[ Submit][ Status][ Discuss]

Description

你是任意性复杂机器公司(Arbitrarily Complex Machines, ACM)的经理,公司使用更加先进的机械设备生产先进的机器。原来的那一台生产机器已经坏了,所以你要去为公司买一台新的生产机器。你的任务是在转型期内尽可能得到更大的收益。在这段时间内,你要买卖机器,并且当机器被ACM公司拥有的时候,操控这些机器以获取利润。因为空间的限制,ACM公司在任何时候都只能最多拥有一台机器。
在转型期内,有若干台可能卖出的机器。作为先进机器的专家,对于每台机器Mi,你已经知道了其价格Pi和可以买入的日期Di。注意,如果不在第Di天买入机器Mi,那么别的人也会买走这一台机器,也就是说,以后你将没有机会购买这台机器了。如果ACM的钱低于一台机器的价格,那么你显然不可能买到这一台机器。
如果你在第Di天买入了机器Mi,那么ACM公司可以从第(Di)+1天开始使用这一台机器。每使用这台机器一天,就可以为公司创造出Gi美元的收益。
你可以决定要在买入之后的某一天,以一定的折扣价卖出这一台机器。收购市场对于每一台机器,都有一个折扣价Ri。你不能在卖出的那一天使用机器,但是你可以在卖出的那一天再买入一台新的。
在转型期结束后,ACM公司会卖掉当前所拥有的机器。你的任务就是最大化转型期间ACM公司可以得到的收入。

Input

输入包含若干组测试用例。每一组测试用例的第一行有3个正整数N,C和D。N是将会卖出的机器的台数(N<=10^5),C是在转型期开始时公司拥有的美元数量(C<=10^9),D是转型期持续的天数(D<=10^9)。
之后的N行每一行描述了一台机器的情况。每一行有4个正整数Di,Pi,Ri和Gi,分别表示这台机器卖出的时间,购买这台机器需要的美元数量,卖出这台机器的折扣价和使用这台机器可以得到的利润。这些数字满足1<=Di<=D,1<=Ri
最后一组测试用例后面的一行由3个0组成,表示输入数据。

Output

对于每一组测试用例,输出测试用例的编号,之后给出ACM公司在第D+1天结束后可以得到的最大数量的美元。
请依照下面给出的样例输出。

Sample Input

6 10 20
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

Case 1: 44

HINT

Source

[ Submit][ Status][ Discuss]



做此题前先写bzoj1492,,NOI2007Cash,这两题差不多

令fi:第i天卖出上一台机器的最大收益

fi = max{fk - Pk + (Di - Dk - 1)*Gk + Rk}

整理得,fk - (Dk+1)*Gk - Pk + Rk = -Di*Gk + fi

记yk = fk - (Dk+1)*Gk - Pk + Rk,xk = Gk

则原式可化为yk = -Di*xk + fi,要让fi最大,截距最大即可

然后就是套用1492的思路了

CDQ,,合并凸包==

听说此题直接叉积会炸。。于是直接写斜率了,记得特判INF

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

const int maxn = 1E5 + 10;
typedef long long LL;
typedef double DB;
const DB eps = 1E-9;
const DB INF = 1E12;

struct Mac{
	LL D,P,R,G; Mac(){}
	Mac(LL D,LL P,LL R,LL G): D(D),P(P),R(R),G(G){}
	bool operator < (const Mac &b) const {return D < b.D;}
}mac[maxn],M[maxn];

struct Point{
	LL x,y; Point(){}
	Point (LL x,LL y): x(x),y(y){}
	bool operator < (const Point &b) const {
		if (x < b.x) return 1;
		if (x > b.x) return 0;
		return y < b.y;	
	}
	Point operator - (const Point &b) {return Point(x - b.x,y - b.y);} 
}s[maxn];
typedef Point Vector;

int n,S,d;
LL f[maxn];

DB getk(Point A,Point B)
{
	DB ax = A.x,ay = A.y;
	DB bx = B.x,by = B.y;
	if (fabs(ax - bx) <= eps) return ay >= by?INF:-INF;
	return (by - ay) / (bx - ax);
}

void Merge(vector  v1,vector  v2,vector  &v)
{
	int tp,tp1,tp2; tp = tp1 = tp2 = 0;
	while (tp1 < v1.size() && tp2 < v2.size()) 
		if (v1[tp1] < v2[tp2]) s[++tp] = v1[tp1++];
		else s[++tp] = v2[tp2++];
	while (tp1 < v1.size()) s[++tp] = v1[tp1++];
	while (tp2 < v2.size()) s[++tp] = v2[tp2++];
	int tot = tp; tp = 0;
	for (int i = 1; i <= tot; i++) {
		while (tp > 1 && getk(s[i],s[tp]) >= getk(s[tp],s[tp-1])) --tp;
		s[++tp] = s[i];
	}
	for (int i = 1; i <= tp; i++) v.push_back(s[i]);
}

LL Query(Point p,Mac q)
{
	return p.y + q.D*p.x;
}

void Solve(int l,int r,vector  &v)
{
	if (l == r) {
		f[l] = max(f[l],f[l-1]);
		if (f[l] >= mac[l].P) {
			Mac k = mac[l];
			v.push_back(Point(k.G,f[l] - (k.D+1)*k.G - k.P + k.R));
		}
		return;
	}
	int mid = (l + r) >> 1,tp = 0;
	vector  v1,v2; v1.clear(); v2.clear();
	Solve(l,mid,v1); 
	if (v1.size()) {
		for (int i = mid+1; i <= r; i++) {
			LL Now = Query(v1[tp],mac[i]);
			while (tp < v1.size() - 1) {
				LL ret = Query(v1[tp+1],mac[i]);
				if (ret < Now) break;
				Now = ret; ++tp; 
			}
			f[i] = max(f[i],Now);
		}
	}
	Solve(mid + 1,r,v2); 
	Merge(v1,v2,v);
}

void Read()
{
	f[1] = S;
	for (int i = 1; i <= n; i++) {
		int D,P,R,G; scanf("%d%d%d%d",&D,&P,&R,&G);
		mac[i] = Mac(D,P,R,G);
	}
}

int main()
{
	#ifdef DMC
		freopen("works1.in","r",stdin);
	#endif
	
	int tot = 0;
	while (scanf("%d%d%d",&n,&S,&d)) {
		if (!n) break; ++tot; Read();
		mac[++n] = Mac(d + 1,0,0,0); 
		mac[++n] = Mac(0,0,0,0);
		sort(mac + 1,mac + n + 1);
		vector  v; v.clear(); 
		for (int i = 2; i <= n; i++) f[i] = 0; Solve(1,n,v);
		printf("Case %d: %lld\n",tot,f[n]);
	}
	return 0;
}

你可能感兴趣的:(dp,CDQ,凸包)