时间限制 : 10000 MS 空间限制 : 65536 KB
问题描述
农夫John准备扩大他的农场,他正在考虑N (1 <= N <= 50,000) 块长方形的土地. 每块土地的长宽满足(1 <= 宽 <=1,000,000; 1 <= 长 <= 1,000,000).
每块土地的价格是它的面积,但FJ可以同时购买多快土地. 这些土地的价格是它们最大的长乘以它们最大的宽, 但是土地的长宽不能交换. 如果FJ买一块3x5的地和一块5x3的地,则他需要付5x5=25.
FJ希望买下所有的土地,但是他发现分组来买这些土地可以节省经费. 他需要你帮助他找到最小的经费.
输入格式
- 第1行: 一个数: N
- 第2..N+1行: 第i+1行包含两个数,分别为第i块土地的长和宽
输出格式
- 第一行: 最小的可行费用.
样例输入
4
100 1
15 15
20 5
1 100
样例输出
500
提示
输入解释: 共有4块土地.
输出解释: FJ分3组买这些土地: 第一组:100x1, 第二组1x100, 第三组20x5 和 15x15.每组的价格分别为100,100,300, 总共500.
题解
其实我是知道了这是一道斜率优化题才开始做的……
第一眼是按长排序后再套个RMQ什么的,结果发现值是变化的,就没有写了。然后试着把宽也搞得单调一下,结果发现规律:当ai≤aj⋀bi≤bjai≤aj⋀bi≤bj时(ii小于,a,ba,b表示长和宽),ii肯定与其他土地一起买且对结果不影响,所以我们可以把从队列中删去,不予以讨论。最后的队列肯定是以长递增、以宽递减的序列。那么状态转移方程就显然了:
好像在删除多余项时各大佬用了一种单调队列的方法,我只会系统unique()unique()……
代码
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<ll,ll> pll;
const int maxn=5e4+5;
ll n,l,r,f[maxn],q[maxn];
pll a[maxn];
db slope(ll x,ll y)
{
return (db)(f[y]-f[x])/(db)(a[x+1].second-a[y+1].second);
}
int main()
{
scanf("%lld",&n);
for(ll i=1;i<=n;i++) scanf("%lld%lld",&a[i].first,&a[i].second);
sort(a+1,a+1+n);
for(ll i=n;i>1;i--)
if(a[i].second>a[i-1].second) a[i-1]=a[i];
n=unique(a+1,a+1+n)-a-1;
for(ll i=1;i<=n;i++)
{
while(l<r&&slope(q[l],q[l+1])<(db)a[i].first) l++;
ll j=q[l];
f[i]=f[j]+a[i].first*a[j+1].second;
while(l<r&&slope(q[r-1],q[r])>slope(q[r],i)) r--;
q[++r]=i;
}
printf("%lld\n",f[n]);
return 0;
}