土地征用

这题有些不一样,睁大眼睛看题,发现不用连续地取,那么我们就可以预处理一下。

把h从大到小排个序,然后从前往后扫一遍,如果当前的这片土地的w值不比前面的最大值大,那么他就可以被包含,无贡献。

这时我们取出了一个h递减,w递增的数列,这时取就必须连续了。

递推式长这样:f[i]=f[j]+b[i].w*b[j+1].h

写成一次函数式:f[j]=-b[i].w*b[j+1].h+f[i]

由于斜率递减,维护上凸包。

看代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e5;
struct data{
    int h,w;
}a[maxn],b[maxn];
int cmp(data x,data y){
    if(x.h==y.h)return x.w>y.w;
    return x.h>y.h;
}
int n,tot,mxw,q[maxn],f[maxn];
signed main(){
    cin>>n;
    for(int i=1;i<=n;i++)
        scanf("%lld%lld",&a[i].h,&a[i].w);
    sort(a+1,a+1+n,cmp);
    for(int i=1;i<=n;i++)
        if(a[i].w>mxw){
            mxw=a[i].w;
            b[++tot]=a[i];
        }
    int l=1,r=1;
    q[l]=0;
    for(int i=1;i<=tot;i++){
        while(l<r&&(f[q[l]]-f[q[l+1]])>=-b[i].w*(b[q[l]+1].h-b[q[l+1]+1].h))l++;
        f[i]=f[q[l]]+b[i].w*b[q[l]+1].h;
        while(l<r&&(f[q[r-1]]-f[q[r]])*(b[q[r]+1].h-b[i+1].h)<=(b[q[r-1]+1].h-b[q[r]+1].h)*(f[q[r]]-f[i]))r--;
        q[++r]=i;
    }
    printf("%lld\n",f[tot]);
    return 0;
}
posted @ 2020-02-29 22:58  syzf2222  阅读(108)  评论(0编辑  收藏  举报