笔记-[SDOI2012]任务安排
笔记-[SDOI2012]任务安排
\(f_i\) 表示分配到第 \(i\) 个任务的最小费用。
令 \(st_i=\sum_{h=1}^iT_h\),\(sc_i=\sum_{h=1}^iC_h\)。
\[\begin{split}
f_i=&\min\{f_j+st_i(sc_i-sc_j)+s(sc_n-sc_j)\}\\
f_i=&f_j+st_isc_i-st_isc_j+s\cdot sc_n-s\cdot sc_j\\
f_j-s\cdot sc_j=&st_isc_j+f_i-st_isc_i-s\cdot sc_n\\
\end{split}
\\
\therefore
\begin{cases}
y=f_j-s\cdot sc_j\\
k=st_i\\
x=sc_j\\
b=f_i-st_isc_i-s\cdot sc_n\\
\end{cases}
\\
\Large y=kx+b
\]
Code
#include <bits/stdc++.h>
using namespace std;
//Start
#define re register
#define il inline
#define mk make_pair
#define pb push_back
#define db double
#define lng long long
#define fi first
#define se second
const int inf=0x3f3f3f3f;
const lng INF=0x3f3f3f3f3f3f3f3f;
//Data
int n,s;
vector<lng> st,sc,f;
//DP
int l,r;
vector<int> q;
il lng X(re int j){return sc[j];}
il lng Y(re int j){return f[j]-sc[j]*s;}
il int Find(re int L,re int R,re lng x){
while(L<R){
re int mid=(L+R)>>1;
if(Y(q[mid+1])-Y(q[mid])>=x*(X(q[mid+1])-X(q[mid]))) R=mid;
else L=mid+1;
}
return q[R];
}
il lng DP(){
l=1,r=0,q=vector<int>(n+7),q[++r]=0,f=vector<lng>(n+7);
for(re int i=1;i<=n;i++){
re int j=Find(l,r,st[i]);
f[i]=f[j]+st[i]*(sc[i]-sc[j])+(sc[n]-sc[j])*s;
while(l<r&&(Y(q[r-1])-Y(q[r]))*(X(q[r])-X(i))
>=(Y(q[r])-Y(i))*(X(q[r-1])-X(q[r]))) r--; q[++r]=i;
}
return f[n];
}
//Main
int main(){
scanf("%d%d",&n,&s),st.pb(0),sc.pb(0);
for(re int i=1,t,c;i<=n;i++) scanf("%d%d",&t,&c),st.pb(st[i-1]+t),sc.pb(sc[i-1]+c);
printf("%lld\n",DP());
return 0;
}
\[\Huge\color{#ddd}{\texttt{---END---}}
\]