【bzoj1597】[Usaco2008 Mar]土地购买

2015.04.14 16:35 Tue | 3次阅读 | 旧日oi | 固定链接 | 源码

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.

题解

先对土地进行排序,第一关键字长度小的在前,第二关键字宽度大的在前
扫面一遍,排除掉长宽被另一矩形全面包围的矩形。于是现在就是长递增,宽递减的序列了
dp[i]=dp[j]+a[i].len*a[j+1].wid;
考虑j1<j2,若j2优于j1,则有(dp[j1]-dp[j2])/(a[j2].wid-a[j1].wid)<a[i].len ,维护一个斜率递增的队列即可,队首最优

我的程序

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
struct node{
    ll len;
    ll wid;
}a[50001],b[50001];
ll dp[50001];
int q[50001],head,tail;
int n,cnt;
bool cmp(const node &a,const node &b)
{
    return a.len<b.len||(a.len==b.len&&a.wid>b.wid);
}
ll slope(int x,int y)
{
    return (dp[y]-dp[x])/(b[x+1].wid-b[y+1].wid);
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    scanf("%lld%lld",&a[i].len,&a[i].wid);
    sort(a+1,a+n+1,cmp);
    cnt=1;
    b[1].len=a[1].len;
    b[1].wid=a[1].wid;
    for(int i=2;i<=n;i++)
    {
        while (cnt&&a[i].wid>=b[cnt].wid) cnt--;
        b[++cnt].len=a[i].len;b[cnt].wid=a[i].wid;
    }
    n=cnt;
    for(int i=1;i<=n;i++)
    {
        while(head<tail&&slope(q[head],q[head+1])<b[i].len) head++;
        dp[i]=dp[q[head]]+b[q[head]+1].wid*b[i].len;
        while(head<tail&&slope(q[tail],i)<slope(q[tail-1],q[tail])) tail--;
        q[++tail]=i;
    }
    cout<<dp[cnt]<<endl;
}```