bzoj1597 [Usaco2008 Mar]土地购买(变形+斜率优化)

来源:互联网 发布:日本知乎 编辑:程序博客网 时间:2024/05/18 09:08

一开始的题目,只是给我们n块随机的地,让我们分组,可以往的1D1D形式的dp一般都会要求每组中序号都是连续的,这样我们才可以进行dp。那此题怎么办呢?首先有个显然的优化:如果x1<=x2&&y1<=y2则(x1,y1)完全可以和(x2,y2)打包在一起购买而不用付出额外的花费,因此(x1,y1)就可以不再考虑了。所以我们把所有的地按x为第一关键字,y为第二关键字进行升序排序,把可以和别的地“打包”购买的都去掉。这之后我们发现,剩下的地有了特殊的性质:x[i]<=x[i+1],y[i]>=y[i+1]。即x是递增的,y是递减的。在这种情况下,我们便可以证明分组一定是连续的才会最优。(如果选择了i,i+2一组,而没有i+1,则不如把i+1也加入这组,因为x[i+1]<=x[i+2],y[i+1]<=y[i],i+1的加入完全不会造成额外的花费。)这样我们就可以进行dp了。f[i]表示购买前i块地所需的最少花费。则f[i]=min{f[j]+y[j+1]x[i]|0j<i}然后进行斜率优化,设k1< k2且k1优于k2,则f[k2]f[k1]y[k1+1]y[k2+1]>x[i]。维护下凸曲线,使得队列中的斜率单增即可。

#include <cstdio>#include <cstring>#include <algorithm>#define N 50010#define ll long longinline int read(){    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*10+ch-'0',ch=getchar();    return x*f;}inline int max(int x,int y){return x>y?x:y;}int n,num=0,q[N],h=0,t=1;ll f[N];struct node{    int x,y;}a[N];inline bool cmp(node x,node y){    return x.x==y.x?x.y<y.y:x.x<y.x;}inline double slope(int k1,int k2){    return (f[k2]-f[k1])*1.0/(a[k1+1].y-a[k2+1].y);}int main(){//  freopen("a.in","r",stdin);    n=read();    for(int i=1;i<=n;++i) a[i].x=read(),a[i].y=read();    std::sort(a+1,a+n+1,cmp);    for(int i=1;i<=n;++i){        while(num&&a[i].y>=a[num].y) --num;        a[++num]=a[i];    }n=num;    q[++h]=0;    for(int i=1;i<=n;++i){        while(h<t&&slope(q[h],q[h+1])<a[i].x) ++h;        f[i]=f[q[h]]+(ll)a[q[h]+1].y*a[i].x;        while(h<t&&slope(q[t],i)<slope(q[t-1],q[t])) --t;        q[++t]=i;    }    printf("%lld\n",f[n]);    return 0;}
阅读全文
0 0