【BZOJ1597】【Tyvj2461】土地购买,第一次的斜率优化DP

传送门1
传送门2
写在前面:看了好久斜率优化DP,感觉还是不太懂
思路:
(受大牛博文启发)
1.除去无效边,li>=lj且ri>=rj,则j可以直接扔掉不要。因此我们可以按l或r排一下序,除去以上情况的无效边,之后剩下的边l,r一定是
一个升序一个降序(我这里是让r降序,l升序)
2.DP方程构建,原始方程:
f[i]=min(f[j]+max(l[j+1]..l[i])max(r[j+1]..r[i]))j[1,i1]
既然已经有序,那么方程变成
f[i]=min(f[j]+l[i]r[j+1])j[1,i1]
复杂度为 O(n2) ,显然不能满足要求,所以就要请出主角——斜率优化

设在当前的状态f[i]时,从f[j]转移比f[k]优。那么该情况等价于f[j]+r[j+1]*l[i]<f[k]+r[k+1]*l[i]
化简一下:l[i]<(f[k]-f[j])/(r[j+1]-r[k+1])。说明,假设j和k满足上述要求,k能够无视了,由于j一定比k更优

以上为第一步优化,即从单调队列队首删除元素
第二步优化中,沙茶的我看了半天标程都没看懂,最后在纸上写了些,并看看其他讲解才勉强有所体悟,设当前元素为i,那么i再经过第一步后已经求出了f[i],并将要加入队尾,再加入队尾前肯定要删去一些不优的元素。

令g[j,k] = (f[k]-f[j])/(x[j] - x[k]) 则g[j,k] > y[i] 表示j比k更优。则k可以舍弃掉
进而我们发现这么一个问题,当c < b < a < i时,如果有g[c, b] > g[b,
a],那么b永远都不会成为计算dp[i]时的决策点。 证明: 如果g[c, b] > g[b, a],那么我们可以分两个方面考虑g[c,
b]与的关系: (1)如果g[c, b] >= y[i],那么决策c不会比决策b差,也就说决策b不可能是决策点 (2)如果g[c, b] <
y[i],那么由于g[c, b] > g[b, a],那么g[b, a] < y[i],那么决策a要比决策b好,所以b还不能作为决策点

注意:
1.开LL很关键,不要吝惜一点点的空间
2.随机数据真的很随机,试了好多组都和标程一样,交上去就WA
3.当你不知道单调队列怎么优化时,让i=0循环是个不错的选择
代码:

#include<bits/stdc++.h>
#define LL long long
using namespace std;
int n,tot,head=1,tail=0;
LL f[500010];
struct os
{
    LL l,r;
}a[500010],b[500010];
struct node
{
    LL x,y;
}q[500010];
int cmp(os x,os y)
{
    return x.r>y.r;
}
main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    scanf("%lld%lld",&a[i].l,&a[i].r);
    sort(a+1,a+n+1,cmp);
    for (int i=1;i<=n;i++)
    if (!tot||b[tot].l<a[i].l)
    b[++tot].l=a[i].l,
    b[tot].r=a[i].r;
    for (int i=0;i<=tot;i++)
    {
        while (head<tail&&q[head+1].y-q[head].y<b[i].l*(q[head].x-q[head+1].x)) head++;
        f[i]=q[head].y+q[head].x*b[i].l;
        while (head<tail&&(f[i]-q[tail-1].y)*(q[tail].x-b[i+1].r)>=(f[i]-q[tail].y)*(q[tail-1].x-b[i+1].r)) tail--;
        q[++tail].y=f[i];
        q[tail].x=b[i+1].r;
    }
    printf("%lld",f[tot]);
}

你可能感兴趣的:(【BZOJ1597】【Tyvj2461】土地购买,第一次的斜率优化DP)