土地征用

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

把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; }

猜你喜欢

转载自www.cnblogs.com/syzf2222/p/12386850.html