A1251. 设计铁路(钱桥) DP+斜率优化

明明是一道裸题,我却做了这么久。感觉自己斜率优化真是弱啊,省选就没做出来,现在做还是这么费力。
我们用 di,ai 分别表示第 i 个车站到终点的距离和人数。
首先按照di降序排序,然后我们用 fi 表示在第i个村庄出修建一个车站,且 1 i 的所有人都开车到车站,此时的总花费。
然后我们维护两个前缀和 si,pi

si=j=i+1ndjaj

pi=j=i+1naj

那么状态转移方程如下:
fi=min{fj+m+sjsi(pjpi)×di}

把与 j 无关的量提到外面:
fi=min{fj+sjpj×di}+m+pi×disi

那么考虑若存在 j<k ,且 k j更优,那么有
fk+skpk×di<fj+sjpj×di

化简可得
(fk+sk)(fj+sj)pkpj>di

然后就可以斜率优化了。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

const int N=40005;
int n,m;
struct node
{
    int d,r;
}p[N];
long long s[N],g[N],f[N];
int q[N];

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

inline bool operator<(node a,node b)
{
    return a.d>b.d;
}

inline long long Y(int j,int k)
{
    return f[j]+s[j]-f[k]-s[k];
}

inline long long X(int j,int k)
{
    return g[j]-g[k];
}

int main()
{
    n=read(); m=read();
    for (int i=1;i<=n;i++)
        p[i].d=read(),p[i].r=read();
    sort(p+1,p+n+1);
    for (int i=n-1;~i;i--)
        s[i]=s[i+1]+p[i+1].d*p[i+1].r,g[i]=g[i+1]+p[i+1].r;
    int t=0,w=0;
    for (int i=1;i<=n+1;i++)
    {
        while (t<w&&Y(q[t+1],q[t])<X(q[t+1],q[t])*p[i].d) t++;
        f[i]=f[q[t]]+s[q[t]]-s[i]+(g[i]-g[q[t]])*p[i].d+m;
        while (t<w&&Y(i,q[w])*X(q[w],q[w-1])>Y(q[w],q[w-1])*X(i,q[w])) w--;
        q[++w]=i;
    }
    cout << f[n+1]-m << endl;
    return 0;
}           
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值