BZOJ 1597: [Usaco2008 Mar]土地购买

Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 6061 Solved: 2298
[Submit][Status][Discuss]
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

FJ分3组买这些土地:

第一组:100x1,

第二组1x100,

第三组20x5 和 15x15 plot.

每组的价格分别为100,100,300, 总共500.

题解

玄学斜率优化,首先我们可以将那些“免费送的地”去了,免费送就是将它按长度降序排序,维护一个宽度
递增的序列,那些去掉的即是免费送的。然后我们考虑转移方程,因为此时的w单调递增,l单调递减。
f[i]=min(f[j]+l[j+1]*w[i])
然后我们再YY出一个k,使得k<j且f[j]更优。
f[j]+l[j+1]*w[i]<f[k]+l[k+1]*w[i],整理得
(f[j]-f[k])/(l[k+1]-l[j+1])>w[i],我们将前面的式子当做斜率,每次判断斜率是否大于新增宽度,
维护一个单调队列,然后用队头更新。

代码

#include<bits/stdc++.h>

using namespace std;
const int MAXN = 50005;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0' && ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

struct Ground{
    int l,w;
}g[MAXN],gr[MAXN];

int n,cnt;
int Q[MAXN],head=1,tail=1;
long long f[MAXN];

inline bool cmp(Ground x,Ground y){
    if(x.l==y.l) return x.w>y.w;
    return x.l>y.l;
}

inline double slope(int x,int y) {
    return (double)(f[x]-f[y])/(double)(gr[y+1].l-gr[x+1].l);
}

int main(){
    n=rd();
    for(register int i=1;i<=n;i++){
        g[i].l=rd();
        g[i].w=rd();
    }
    sort(g+1,g+1+n,cmp);
    for(register int i=1;i<=n;i++){
        if(g[i].w<=gr[cnt].w) continue;
        gr[++cnt].l=g[i].l;
        gr[cnt].w=g[i].w;
    }
    for(register int i=1;i<=cnt;i++){
        while(head<tail && slope(Q[head],Q[head+1])<=gr[i].w) head++; 
        f[i]=f[Q[head]]+(long long)gr[i].w*gr[Q[head]+1].l;
        while(head<tail && slope(Q[tail-1],Q[tail])>=slope(Q[tail],i)) tail--;
        Q[++tail]=i;
    }
    printf("%lld",f[cnt]);
    return 0;
}
posted @ 2018-06-15 21:47  Monster_Qi  阅读(106)  评论(0编辑  收藏  举报