斜率优化DP
斜率优化DP
适用场景
当DP方程提出常数项后,可以化成\(f[j]=min\{a[i]b[j]+f[i]\}\)
即可以使用斜率优化,正常情况下,要使用\(O(n^2)\)的复杂度,而现在可以优化成\(O(n)\)
显然,方程式可以化成\(y=kx+b\)的形式,这显然是一条直线的解析式
画一个坐标轴,以\(b[j]\)为x轴,\(f[j]\)为y轴,\(a[i]\)为斜率,然后找出最小的截距b(x=0时的y的值)即可
过程
我也不知道为什么,反正用单调队列维护一个凸包
然后二分找到一个P,使前面的斜率<P的斜率<后面的斜率即是最佳答案
然后从队尾删去所有满足前两个点的斜率>后两个点的斜率就行
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n,s,t[1000000],c[1000000],ls;
ll f[1000000];//在i+1重启机器,前i个任务分成若干组后的费用+分成若干组后多出的后续费用的最小值
ll q[1000000],l,r;
ll doo(ll x){
if(l==r){
return q[l];
}
ll L=l,R=r,ans=0;
while(L<=R){
ll mid=(L+R)>>1;
if(f[q[mid+1]]-f[q[mid]]<=ls*(c[q[mid+1]]-c[q[mid]])){
ans=mid+1;
L=mid+1;
}
else{
R=mid-1;
}
}
return q[ans];
}
int main(){
cin>>n>>s;
for(int i=1;i<=n;i++){
cin>>t[i]>>c[i];
t[i]=t[i]+t[i-1];
c[i]=c[i]+c[i-1];
}ae
l=r=1;
q[1]=0;
for(int i=1;i<=n;i++){
ls=s+t[i];
ll ans=doo(i);
f[i]=f[ans]-ls*c[ans]+t[i]*c[i]+s*c[n];
while(l<r&&(f[q[r]]-f[q[r-1]])*(c[i]-c[q[r]])>=(c[q[r]]-c[q[r-1]])*(f[i]-f[q[r]])){
r--;
}
q[++r]=i;
}
cout<<f[n];
}
可以自由转载

浙公网安备 33010602011771号