[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;
}
标签:ch,int,tot,土地,Land,单调,USACO08MAR,排序,Acquisition 来源: https://www.cnblogs.com/PPXppx/p/11008285.html