BZOJ1597 [Usaco2008 Mar]土地购买

斜率优化dp。
显然,如果一个土地的长,宽都小于另一个土地,那么就一定能被免费打包带走,排个序(或许只有我因为这个调了半天),去一下这些没用的。
一个\(O(n^2)\)的显然做法:以f[i]表示买了前i块土地最小花费。
\(f_i=f_j+len_i \cdot width_{j+1} (1<=j<=i)\)
然后转化一下式子,弄成\(-f_j=len_i \cdot width_{j+1}-f_i\),就成了斜率优化的形式,维护一个下凸包即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define int long long
using namespace std;
const int N=50005;
struct TD {
	int len,width;
} t[N],d[N];
int n;
int q[N<<2],l,r,cnt,f[N];
bool cmp(TD x,TD y) {
	return x.width>y.width||(x.width==y.width&&x.len>y.len);
}
double slope(int x,int y) {
	return (double)(-f[x]+f[y])/(double)(d[1+x].width-d[y+1].width);
}
main() {
	scanf("%lld",&n);
	for(int i=1; i<=n; i++)
		scanf("%lld%lld",&t[i].width,&t[i].len);
	sort(t+1,t+1+n,cmp);
	for(int i=1; i<=n; i++) {
		if(t[i].len>d[cnt].len) d[++cnt]=t[i];
	}
	n=cnt;
	for(int i=1; i<=n; i++) {
		while(l<r&&slope(q[l],q[l+1])<=d[i].len) l++;
		f[i]=f[q[l]]+d[i].len*d[q[l]+1].width;
		while(l<r&&slope(q[r-1],q[r])>=slope(q[r],i))r--;
		q[++r]=i;
	}
	cout<<f[n];
}
posted @ 2018-07-21 20:41  SWHsz  阅读(123)  评论(0编辑  收藏  举报