洛谷2900 [USACO08MAR]Land Acquisition

题解 动态规划 动态规划-斜率优化DP 省选/NOI-
题目链接 编辑文章

题意

有 $N$ 块矩形土地,面积为 $W_i\times H_i$ 。可以购买单个土地,价格为面积;也可以将多个土地合并起来买,价格为 $\max W\times \max H$ 。要将所有土地买下来,求最小花费。

$N\le 50000$ 。

题解

对于两块土地 $i,j$ ,如果 $H_i\le H_j,W_i\le W_j$ ,那么买 $j$ 的时候顺便把 $i$ 带上就行了,$i$ 就可以删去。

具体的操作为先按 $H$ 从小到大排序,然后依次入栈,入栈前从栈顶依次把 $W_{top}\le W_i$ 的土地弹出,最后剩下的土地就是有用的。

可以发现剩下的土地都是按 $H$ 从大到小,$W$ 从小到大排序的。合并起来买的土地一定是连续的,因为合并买 $i,j$ ,与买 $[i,j]$ 的价格都是 $H_i\times W_j$ 。

用 $f[i]$ 表示前 $i$ 块土地的最小花费,方程式为:

$$f[i]=\min f[j]+H_{j+1}\times W_i$$

$$f[j]=-W_i\times H_{j+1}+f[i]$$

可以斜率优化,斜率 $-W_i$ 单调。

#include<bits/stdc++.h>
#define ll long long

using namespace std;

inline ll read()
{
    char ch=getchar(); ll f=1,x=0;
    while (ch<'0' || ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
    while (ch>='0' && ch<='9') { x=x*10+ch-'0'; ch=getchar(); }
    return f*x;
}

struct node {
    ll x,y;
} s[50005];
stack <ll> t;
ll n,f[50005],h[50005],w[50005],q[50005];

inline double slope(int x,int y) { return -1.0*(f[y]-f[x])/(h[y+1]-h[x+1]); }

signed main()
{
    n=read();
    for (ll i=1;i<=n;i++) s[i].x=read(),s[i].y=read();
    sort(s+1,s+n+1,[](const node &x,const node &y){ return x.x==y.x ? x.y<y.y : x.x<y.x; });
    for (ll i=1;i<=n;i++)
    {
        while (!t.empty() && s[t.top()].y<=s[i].y) t.pop();
        t.emplace(i);
    }
    ll cnt=0;
    for (;!t.empty();t.pop()) h[++cnt]=s[t.top()].x,w[cnt]=s[t.top()].y;
    n=cnt;
    ll l=1,r=1; q[1]=0;
    for (ll i=1;i<=n;i++)
    {
        while (l<r && slope(q[l],q[l+1])<=w[i]) l++;
        f[i]=f[q[l]]+h[q[l]+1]*w[i];
        while (l<r && slope(q[r-1],q[r])>=slope(q[r],i)) r--;
        q[++r]=i;
    }
    return !printf("%lld",f[n]);
}

新评论

称呼不能为空
邮箱格式不合法
网站格式不合法
内容不能为空