BZOJ-1597: [Usaco2008 Mar]土地购买

[文章目录]

Description

农夫John准备扩大他的农场,他正在考虑N (1 <= N <= 50,000) 块长方形的土地. 每块土地的长宽满足(1 <= 宽 <= 1,000,000; 1 <= 长 <= 1,000,000). 每块土地的价格是它的面积,但FJ可以同时购买多快土地. 这些土地的价格是它们最大的长乘以它们最大的宽, 但是土地的长宽不能交换. 如果FJ买一块3x5的地和一块5x3的地,则他需要付5x5=25. FJ希望买下所有的土地,但是他发现分组来买这些土地可以节省经费. 他需要你帮助他找到最小的经费

斜率优化DP,先将能完全覆盖的农田去除,然后发现农场的x递增,y递降。

dp[i]表示前i个农场的最小花费。

dp[i]=dp[j]+y[j]*x[i](0<=j<=i-1)

然后发现y[j]是递减的,x[i]是递增的,符合条件。

搞一下就出来了,哈哈。

发现一个捷径,第一个while直接代入解析式判断。

第二个,嘿嘿嘿,因为判断交点是有分母的,所以要判断分母的正负,考虑变号。

我们知道k是单调的,但是并不知道是怎么单调的,那???

所有分母都是后者-前者的形式,所以,两边同乘分母时直接不变号。

然后,斜率优化需要注意上帝视角是在下面还是上面,k恒正还是恒负。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
using namespace std;
int n,tail,h,t;
struct node
{
	LL x,y;
}a[500100];
bool cmp(node x,node y)
{
	return x.x==y.x ? x.y<y.y : x.x<y.x;
}
LL dp[500100];
int q[500100];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld%lld",&a[i].x,&a[i].y);
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++)
	{
		while(tail&&a[tail].y<=a[i].y) tail--;
		a[++tail]=a[i];
	}
	for(int i=1;i<=tail;i++)
	{
		while(h<t&&a[q[h]+1].y*a[i].x+dp[q[h]]>=a[q[h+1]+1].y*a[i].x+dp[q[h+1]]) h++;
		dp[i]=dp[q[h]]+a[i].x*a[q[h]+1].y;
		while(h<t&&(dp[i]-dp[q[t]])*(a[q[t-1]+1].y-a[q[t]+1].y)<=(dp[q[t]]-dp[q[t-1]])*(a[q[t]+1].y-a[i+1].y)) t--;
		q[++t]=i;
	}
	printf("%lld",dp[tail]);
	return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注