[斜率优化][DP]luogu P2900 [USACO08MAR]Land Acquisition G

题面

https://www.luogu.com.cn/problem/P2900

分析

首先把长宽同时小于等于别人的土地除去,因为买下它的代价必然可以被覆盖

可以用按 w,l 双关键字降序排序除去,除完以后发现此时 w 单调递减 l 单调递增

考虑转移方程 $f[i]=min(f[j]+w[j]*l[i])(1<=j<i)$

这个是一个很显然的斜率优化方程形式,则若 $1leq j < k < i$ ,若 j 比 k 更优

$f[j]+w[j+1]*l[i] < f[k]+w[k+1]*l[i]$

$f[j]-f[k]<l[i]*(w[k+1]-w[j+1])$

$frac{f[j]-f[k]}{w[k+1]-w[j+1]}>l[i]$

单调队列优化一下即可

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=5e4+10;
struct Rect {
    ll w,l;
}a[N];
int n,m,h,t,q[N];
ll f[N];

bool CMP(Rect a,Rect b) {return a.w>b.w||a.w==b.w&&a.l>b.l;}

double Slope(int i,int j)  {return (f[i]-f[j])/(a[j+1].w-a[i+1].w);}

int main() {
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%lld%lld",&a[i].w,&a[i].l);
    sort(a+1,a+n+1,CMP);
    for (int i=1;i<=n;i++) if (a[m].l<a[i].l) a[++m]=a[i];
    h=t=1;
    for (int i=1;i<=m;i++) {
        while (h<t&&Slope(q[h],q[h+1])<=a[i].l) h++;
        f[i]=f[q[h]]+a[q[h]+1].w*a[i].l;
        if (i==m) break;
        while (h<t&&Slope(q[t-1],q[t])>=Slope(q[t],i)) t--;
        q[++t]=i;
    }
    printf("%lld",f[m]);
}
View Code
在日渐沉没的世界里,我发现了你。
原文地址:https://www.cnblogs.com/mastervan/p/14594053.html