[斜率优化][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)$
这个是一个很显然的斜率优化方程形式,则若 $1\leq 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]); }
在日渐沉没的世界里,我发现了你。