[USACO08MAR]土地征用Land Acquisition

洛咕

双倍经验

题意:\(N(<=50000)\)块长方形土地,要么单买一块土地,花费为该长方形土地面积,要么并购一组土地,花费为该组长方形土地中最大的长乘上最大的宽,求最小花费.

分析:可能是我语文理解能力不够好,反正我读题的时候没有看出来 这些土地可以不按顺序来买.既然有这个隐含条件,那么很容易想到,如果一块土地它的宽度和长度都比别人小,那么就不用管它了(因为它一定可以跟别人一起被收购)

于是开一个结构体,按照w(宽度)为第一关键字,l(长度)为第二关键字从小到大排序,排序之后,将那种不用管的土地踢出考虑范围:

	for(int i=1;i<=n;i++){
		while(tot&&b[tot].l<a[i].l)tot--;
		b[++tot].w=a[i].w;b[tot].l=a[i].l;
    }

因为tot一定小于等于i,而排序后w一定是单调递增的,所以b[tot].w一定小于a[i].w,就只用比较l了.经过这个操作之后,我们需要考虑的土地就只有tot个了,宽度和长度信息存到b数组中,且b数组中w一定是单调递增,l一定是单调递减的.

\(f[i]\)表示考虑到(tot中)前i块土地时的最小花费.则有\(f[i]=f[j]+b[i].w*b[j+1].l\)(因为w递增,l递减,所以j+1到i的土地中w在b[i]取最大,l在b[j+1]取最大)

设k<j且j比k更优,即

\(f[j]+b[i].w*b[j+1].l<f[k]+b[i].w*b[k+1].l\)

整理一下这个式子得到,

\(\frac{f[j]-f[k]}{b[k+1].l-b[j+1].l}<b[i].w\)(其中\(b[k+1].l>b[j+1].l\),所以不用变号)

#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline int read(){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
    return s*w;
}
const int N=50005;
int n,tot,l,r,q[N];LL f[N];
struct ppx{
    int w,l;
}a[N],b[N];
inline bool cmp(const ppx &x,const ppx &y){return x.w==y.w?x.l<y.l:x.w<y.w;}
int main(){
    n=read();
    for(int i=1;i<=n;i++)a[i].w=read(),a[i].l=read();
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++){
		while(tot&&b[tot].l<a[i].l)tot--;
		b[++tot].w=a[i].w;b[tot].l=a[i].l;
    }
    for(int i=1;i<=tot;i++)f[i]=1e18;
    for(int i=1;i<=tot;i++){
		while(l<r&&(f[q[l+1]]-f[q[l]])<=(1ll*b[i].w*(b[q[l]+1].l-b[q[l+1]+1].l)))l++;
		f[i]=f[q[l]]+1ll*b[i].w*b[q[l]+1].l;
		while(l<r&&1ll*(f[q[r]]-f[q[r-1]])*(b[q[r]+1].l-b[i+1].l)>=1ll*(f[i]-f[q[r]])*(b[q[r-1]+1].l-b[q[r]+1].l))r--;
		q[++r]=i;
    }
    printf("%lld\n",f[tot]);
    return 0;
}

posted on 2019-06-12 10:56  PPXppx  阅读(113)  评论(0编辑  收藏  举报