土地征用
这题有些不一样,睁大眼睛看题,发现不用连续地取,那么我们就可以预处理一下。
把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;
}