batch:$n<=10000$
斜率优化入门题
$n^{3}$的dp轻松写出
但是枚举这个分成多少段很不方便
我们利用费用提前的思想,提前把这个烦人的$S$在后面的贡献先算掉
设$sv[i],st[i]$为费用、时间的前缀和
于是我们就可以得出一个$n^{2}$的方程
$f[i]=f[j]+(sv[i]-sv[j])*st[i]+(sv[n]-sv[j])*S$
拆开:$f[i]=f[j]+sv[i]*st[i]-sv[j]*st[i]+sv[n]*S-sv[j]*S$
移项:$f[j]=(S+st[i])*sv[j]+f[i]-sv[i]*st[i]-sv[n]*S$
再用$y=k*x+b$的套路带进去
$f[j]=(S+st[i])*sv[j]+f[i]-sv[i]*st[i]-sv[n]*S$
$y=k*x+b$
$y=f[j]$
$x=sv[j]$
$k=S+st[i]$(显然随着$i$增大而单调递增)
$b=f[i]-sv[i]*st[i]-sv[n]*S$
于是问题又转化成:找到一个使$b$最小的$(x,y)$
这样就能使$f[i]$最小
考虑到$k$单调递增,$x$也单调递增
我们就可以快乐地用单调队列维护下凸包辣
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef double db;
#define N 10005
db sv[N],st[N],f[N];
int n,S,L,R,h[N];
inline db X(int x){return sv[x];}
inline db Y(int x){return f[x];}
inline db K(int x,int y){return (Y(x)-Y(y))/(X(x)-X(y));}
int main(){
scanf("%d%d",&n,&S);
for(int i=;i<=n;++i){
scanf("%lf%lf",&st[i],&sv[i]);
st[i]+=st[i-]; sv[i]+=sv[i-];
}L=R=;
for(int i=;i<=n;++i){
while(L<R&&K(h[L],h[L+])<=S+st[i]) ++L;
f[i]=f[h[L]]+(sv[i]-sv[h[L]])*st[i]+(sv[n]-sv[h[L]])*S;
while(L<R&&K(h[R-],h[R])>K(h[R],i)) --R;
h[++R]=i;
}printf("%.0lf",f[n]);
return ;
}