您的位置:首页 > 其它

1597: [Usaco2008 Mar]土地购买 斜率优化dp

2016-12-07 21:50 375 查看

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.

分析

这题列,明显是题斜率优化,一听逼格就很高对不对,其实很简单的。。怎么做呢?

首先很容易得到,若有两块土地长宽分别为l1,w1,l2,w2,若满足l1>=l2且w1>=w2则第二块土地可以忽略不计。

那么就先把所有没用的土地都去掉,并按长从小到大排序,那么宽自然就是递减的了。显然每次必然选取连续的一段,设f[i]表示前i块分成若干段的最小花费,显然可以得到f[i]=min(f[j]+w[j+1]∗l[i])

我们设有j < k且对于i而言选j比选k更优,那么必然有f[j]+w[j+1]∗l[i]

#include <bits/stdc++.h>

#define N 50005

#define ll long long
#define INF 0x3f3f3f3f

struct NOTE
{
ll l,w;
}map
;

ll f
;
int Q
;

ll read()
{
ll k=1,x=0;
char ch;
ch=getchar();
while(ch<'0' || ch>'9')
{
if(ch=='-')
k=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*k;
}

bool camp(NOTE a,NOTE b)
{
return a.l<b.l || a.l==b.l && a.w<b.w;
}

ll getl(int i,int j)
{
return f[i]-f[j];
}

ll getr(int i,int j)
{
return map[j+1].w-map[i+1].w;
}

int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&map[i].l,&map[i].w);
}
std::sort(map+1,map+n+1,camp);
ll mx=0;
int nn=n;
for(int i=n;i>=1;i--)
{
if(map[i].w<=mx)
{
map[i].l=INF;
nn--;
}
else mx=map[i].w;
}
std::sort(map+1,map+n+1,camp);
n=nn;
int head=1,tail=1;
Q[1]=0;
for(int i=1;i<=n;i++)
{
while(head<tail && getl(Q[head],Q[head+1])>=getr(Q[head],Q[head+1])*map[i].l)
head++;
f[i]=f[Q[head]]+(ll)map[i].l*map[Q[head]+1].w;
while(head<tail && getl(Q[tail-1],Q[tail])*getr(Q[tail],i)>getl(Q[tail],i)*getr(Q[tail-1],Q[tail]));
tail--;
Q[++tail]=i;
}
std::cout<<f
<<std::endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: