bzoj1597[Usaco2008 Mar] 土地购买

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1597

题目大意:
N (1 <= N <= 50,000) 块长方形的土地. 每块土地的长宽满足(1 <= 宽 <= 1,000,000; 1 <= 长 <= 1,000,000). 每块土地的价格是它的面积,可以同时购买多快土地. 这些土地的总价格是它们之中最大的长乘以它们之中最大的宽。

============================================

题解:

斜率优化

看到这种题肯定要先想到排序,而且我们很容易可以发现,如果有某个土地的长和宽都比另一土地的长和宽要小的话,那么这个土地的购买是相当于不需要花费的,即对答案没有贡献。那么我们将这样的土地删掉之后得到的土地序列,长是递增的,宽则是递减的。

(诶长宽什么的随便了就a跟b..)

于是容易得到方程:f[i]=f[j]+a[i]*b[j+1];

然后..就好了啊..什么-a[i]*b[j+1]+f[i]=f[j]移一下项


代码里mx[]存的是一开始的土地,nw[]是排完序删完的土地

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
typedef long long LL;
using namespace std;
#define maxn 51000

int q[maxn];LL f[maxn];
struct node {LL a,b;}mx[maxn],nw[maxn];
double Y(int j){return f[j];}
double X(int j){return -nw[j+1].b;}
double slop(int j1,int j2)
{
	return (Y(j2)-Y(j1))/(X(j2)-X(j1));
}
bool cmp(node x,node y)
{
	if (x.a!=y.a) return x.a<y.a;
	return x.b<y.b;
}
int main()
{
	int n,len,i,l,r;
	scanf("%d",&n);
	for (i=1;i<=n;i++)
	 scanf("%lld%lld",&mx[i].a,&mx[i].b);
	sort(mx+1,mx+1+n,cmp);
	len=1;nw[1]=mx[1];
	for (i=2;i<=n;i++)
	{
	   while (len>0 && nw[len].b<=mx[i].b) len--;
	   nw[++len]=mx[i];
	}
	memset(f,0,sizeof(f));
	l=1;r=1;q[1]=0;
	for (i=1;i<=len;i++)
	{
		while (l<r && slop(q[l],q[l+1])<nw[i].a) l++;
		int j=q[l];
		f[i]=f[j]+nw[i].a*nw[j+1].b;
		while (l<r && slop(q[r-1],q[r])>slop(q[r],i)) r--;
		q[++r]=i;
	}printf("%lld\n",f[len]);
	return 0;
}



posted @ 2016-09-22 16:58  OxQ  阅读(102)  评论(0编辑  收藏  举报