zoukankan      html  css  js  c++  java
  • 土地征用Land Acquisition(斜率优化DP)

    题目链接:土地征用Land Acquisition
    题面:约翰准备扩大他的农场,眼前他正在考虑购买N块长方形的土地。如果约翰单买一块土 地,价格就是土地的面积。但他可以选择并购一组土地,并购的价格为这些土地中最大的长 乘以最大的宽。比如约翰并购一块3 × 5和一块5 × 3的土地,他只需要支付5 × 5 = 25元, 比单买合算。 约翰希望买下所有的土地。他发现,将这些土地分成不同的小组来并购可以节省经费。 给定每份土地的尺寸,请你帮助他计算购买所有土地所需的最小费用。


    题解:我们先以(x)升序排序,对于每一个(i),如果存在一个(j)使得(x_i<=x_j,y_i<=y_j),那么很明显,(i)(j)一起购买是不会产生价值的,那么我们可以把(i)删去,最后我们就得到一个(i)升序,(y)降序的数组。问题便转化为将序列分为若干份([L_i,R_i]),使得(ans=sum({x_{R_i}} imes y_{L_i}))最小。
    我们可以很轻松地得到一个DP方程式:设(f[i])表示到第(i)个结尾时的最小代价,那么转移便是(f[i]=min_{j=0}^{i-1}{f[j]+x[i]cdot y[j+1]})
    很明显这一个方程式是(O(n^2))的,对于(n le 5 cdot 10^4)的数据范围是肯定跑不过的(除非你有十分特殊的卡常技巧)
    我们引入(j,k(j<k<i))两个变量,考虑当前在第(i)位上进行动规,取(k)比取(j)更优的情况。
    (f[j]+x[i]*y[j+1] > f[k]+x[i]*y[k+1])
    (f[j]-f[k]>x[i] imes (y[k+1]-y[j+1]))因为我们之前已经说明了(y)是降序的,所以(y[k+1]-y[j+1]<0)
    所以(frac{f[j]-f[k]}{y[k+1]-y[j+1]}<x[i])
    但是,我们的(x[i])是单调递增的
    下面就可以很开心地用单调队列维护啦。
    code

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define Maxn 50000
    #define ll long long
    #define eps 1e-8
    struct Node{
    	int x,y;
    	friend bool operator <(Node p,Node q){
    		if(p.x==q.x){
    			return p.y<q.y;
    		}
    		return p.x<q.x;
    	}
    }a[Maxn+5];
    int n;
    ll f[Maxn+5];
    int q[Maxn+5],h,t;
    double slope(int x,int y){
    	return (f[x]-f[y])*1.0/(a[y+1].y-a[x+1].y);
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d%d",&a[i].x,&a[i].y);
    	}
    	sort(a+1,a+1+n);
    	int m=0,maxn=0;
    	for(int i=n;i>0;i--){
    		if(a[i].y<=maxn){
    			a[i].x=(1<<30);
    			m++;
    		}
    		else{
    			maxn=a[i].y;
    		}
    	}
    	sort(a+1,a+1+n);
    	n-=m;
    	h=1;
    	q[++t]=0;
    	for(int i=1;i<=n;i++){
    		while(h<t&&slope(q[h],q[h+1])<=a[i].x+eps){
    			h++;
    		}
    		f[i]=f[q[h]]+a[q[h]+1].y*1ll*a[i].x;
    		while(h<t&&slope(q[t-1],q[t])>=slope(q[t-1],i)){//这两段似乎可以交叉相乘避免精度问题,不过我懒得那么写了
    			t--;
    		}
    		q[++t]=i;
    	}
    	cout<<f[n]<<endl;
    	return 0;
    }
    
  • 相关阅读:
    WebSocket
    使用fiddler将网站上的css js重定向至本地文件
    chrome浏览器调试线上文件映射本地文件
    xul 创建一个按钮
    模板小程序】求小于等于N范围内的质数
    哈希-------开放寻址法-------暴雪哈希
    建造者模式(build pattern)-------创造型模式
    抽象工厂模式(abstract factory pattern)------创造型模式
    工厂模式(factory pattern) ------创造型模式
    文件名中含有连续字符abc,相应文件中也含有字符串abc
  • 原文地址:https://www.cnblogs.com/withhope/p/11767880.html
Copyright © 2011-2022 走看看