您的位置:首页 > 其它

BZOJ1597: [Usaco2008 Mar]土地购买

2017-09-29 18:26 190 查看
Description

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

Input

第1行: 一个数: N

第2..N+1行: 第i+1行包含两个数,分别为第i块土地的长和宽

Output

第一行: 最小的可行费用.

Sample Input

4

100 1

15 15

20 5

1 100

输入解释:

共有4块土地.

Sample Output

500

HINT

FJ分3组买这些土地: 第一组:100x1, 第二组1x100, 第三组20x5 和 15x15 plot. 每组的价格分别为100,100,300, 总共500.

题目传送门

斜率优化。

以后证明决策单调性的公式我都不写了。

只在代码里简易讲一下斜率的推公式过程。

代码如下:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
/*
f[i]=min(f[i],f[j]+a[i].x*a[j+1].y);
j1<j2<i
f[j2]+a[i].x*a[j2+1].y<=f[j1]+a[i].x*a[j1+1].y;
(f[j2]-f[j1])/(a[j1+1].y-a[j2+1].y)
*/
struct node
{
ll x,y;
}a[51000],b[51000];
int n,m;
int head,tail,list[51000];
ll f[51000];
double slope(int j1,int j2)
{
return double((f[j2]-f[j1])/(b[j1+1].y-b[j2+1].y));
}
/*
int cmp(const void *x1,const void*x2)
{
node n1=*(node*)x1;
node n2=*(node*)x2;
if(n1.x!=n2.x)return n1.x-n2.x;
else return n1.y-n2.y;
}*/
bool cmp(node n1,node n2)
{
if(n1.x>n2.x)return 0;
if(n1.x<n2.x)return 1;
if(n1.y>n2.y)return 0;
if(n1.y<n2.y)return 1;
return 0;
}
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+1+n,cmp);
m=1;b[1]=a[1];
for(int i=2;i<=n;i++)
{
while(m>0&&b[m].y<=a[i].y)m--;
b[++m]=a[i];
}
head=1;tail=1;
for(int i=1;i<=m;i++)
{
while(head<tail&&slope(list[head],list[head+1])<b[i].x)head++;
int j=list[head];
f[i]=f[j]+b[i].x*b[j+1].y;
while(head<tail&&slope(list[tail],i)<slope(list[tail-1],list[tail]))tail--;
list[++tail]=i;
}
printf("%lld\n",f[m]);
return 0;
}


by_lmy
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: