明明是一道裸题,我却做了这么久。感觉自己斜率优化真是弱啊,省选就没做出来,现在做还是这么费力。
我们用di,ai分别表示第i个车站到终点的距离和人数。
首先按照
然后我们维护两个前缀和si,pi。
si=∑j=i+1ndj∗aj
pi=∑j=i+1naj
那么状态转移方程如下:
fi=min{fj+m+sj−si−(pj−pi)×di}
把与j无关的量提到外面:
那么考虑若存在j<k,且k比
fk+sk−pk×di<fj+sj−pj×di
化简可得
(fk+sk)−(fj+sj)pk−pj>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;
}