P2900 [USACO08MAR] Land Acquisition G

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

1.若h w 均小于某一个地 就可以去掉 具体做法可以是,按高为第一关键字,宽为第二关键字从大到小排序,然后上双指针扫一遍。
2.剩下的就是一个高度递减、宽度递增的矩形序列 连续选择最有
f[i]:前i个最小值
f[i]=min(f[j-1]+h[j]*w[i]) (j<=i) O(N^2)
f[j-1]=-w[i]*h[j]+f[i] k->w[i] h[j]->x f[j-1]->y
f[j-1]=w[i]*(-h[j])+f[i] 用单调时最好时单调增 将(f[j-1],-h[j]) 看作点
显然维护 斜率单调增加即可 斜率>=w[i]的最小值   

head:若斜率<w[i] 直接++
tail:不满足斜率严格单增 --
斜率k[pos_que]单调队列在pos的斜率关系 f[i]标号 前i个
f[-1]在计算中当作0处理
*/
/*
4 
100 1 
15 15 
20 5 
1 100 

500
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string.h>
#include<queue>
#include<vector>
#include<bits/stdc++.h>
typedef long long ll;
#define ddd printf("-----------------------\n");
using namespace std;
const int maxn=1e1 +10;
const int mod=998244353;
const int inf=0x3f3f3f3f;

int n,q[50010];
double f[50010],k[50010];
struct node{
    int w,h;
    bool operator<(const node &a)const{
        return h>a.h||(h==a.h)&&(w>a.w);
    }
}a[50010];

double cal(int i,int j){
    return 1.0*(f[j-1]-f[i-1])/(a[i].h-a[j].h);
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i].w>>a[i].h;
    sort(a+1,a+1+n);
    int tmp=1;for(int i=1;i<=n;i++) if(a[tmp].w<a[i].w) a[++tmp]=a[i]; 
    n=tmp;
    
    int head=1,tail=0;
    for(int i=1;i<=n;i++)
    {
        //j<=i 所以一定要先tail++
        while(head<tail&&k[tail-1]>=cal(q[tail],i)) tail--;
        k[tail]=cal(q[tail],i),q[++tail]=i;//k[pos]:pos向右的一段斜率
        while(head<tail&&k[head]<a[i].w) head++;
        f[i]=f[q[head]-1]+(double)a[q[head]].h*a[i].w;
    }
    printf("%.0lf\n",f[n]);
    
    return 0;
}

 

posted @ 2023-12-20 05:32  JMXZ  阅读(14)  评论(0)    收藏  举报