传送门:bzoj2726
题解
斜率优化。
按照“费用提前计算”的规则将每个任务的
S
S
S花费提前处理,列出
d
p
dp
dp转移:
d
p
i
=
d
p
j
−
(
S
+
T
i
)
C
j
+
T
i
C
i
+
S
C
n
dp_i=dp_j-(S+T_i)C_j+T_iC_i+SC_n
dpi=dpj−(S+Ti)Cj+TiCi+SCn
其中
C
i
=
∑
j
=
1
i
F
j
,
T
i
=
∑
j
=
1
i
T
j
C_i=\sum\limits_{j=1}^iF_j,T_i=\sum\limits_{j=1}^iT_j
Ci=j=1∑iFj,Ti=j=1∑iTj
转成斜率的形式:
F
j
=
(
S
+
T
i
)
C
j
−
T
i
C
i
−
S
C
n
+
F
i
F_j=(S+T_i)C_j-T_iC_i-SC_n+F_i
Fj=(S+Ti)Cj−TiCi−SCn+Fi
因为 C j C_j Cj是单调的,其实可以在凸包上二分,cdq分治也可以做。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+100;
typedef long long ll;
typedef double db;
int n,S,top,stk[N];
int c[N],t[N];ll f[N];
struct P{
int x;ll y;int k;ll b;int id;
bool operator<(const P&ky)const{
return k<ky.k;
}
}p[N],rep[N];
char cp;
template<class yyy>
inline void rd(yyy &x)
{
cp=getchar();int pr=0;x=0;
for(;!isdigit(cp);cp=getchar()) if(cp=='-') pr=1;
for(;isdigit(cp);cp=getchar()) x=(x<<3)+(x<<1)+(cp^48);
if(pr) x=-x;
}
inline db slp(int A,int B)
{
if(p[A].x==p[B].x) return (p[B].y>=p[A].y)?(1e18):(-1e18);
return (p[B].y-p[A].y)/(db)(p[B].x-p[A].x);
}
void sol(int l,int r)
{
if(l==r) {p[l].y=f[l];return;}
int mid=(l+r)>>1,k,i=l,j=mid+1;
for(k=l;k<=r;++k)
if(p[k].id<=mid) rep[i++]=p[k];
else rep[j++]=p[k];
for(k=l;k<=r;++k) p[k]=rep[k];
sol(l,mid);
top=0;
for(k=l;k<=mid;++k){
for(;top>1 && slp(stk[top-1],stk[top])>=slp(stk[top],k);--top);
stk[++top]=k;
}
for(k=mid+1,i=1;k<=r;++k){
for(;i<top && slp(stk[i],stk[i+1])<=(db)p[k].k;++i);
f[p[k].id]=min(f[p[k].id],p[stk[i]].y-(ll)p[k].k*p[stk[i]].x+p[k].b);
}
sol(mid+1,r);
i=l;j=mid+1;
for(k=l;k<=r;++k)
if((j>r) || (i<=mid && p[i].x<p[j].x)) rep[k]=p[i++];
else rep[k]=p[j++];
for(k=l;k<=r;++k) p[k]=rep[k];
}
int main(){
int i,j;
memset(f,0x7f,sizeof(f));
f[0]=t[0]=c[0]=0;
rd(n);rd(S);
for(i=1;i<=n;++i){
rd(t[i]);rd(c[i]);
t[i]+=t[i-1];c[i]+=c[i-1];
}
ll res=(ll)S*c[n];
for(i=1;i<=n;++i) p[i]=(P){c[i],0,S+t[i],(ll)t[i]*c[i]+res,i};
sort(p+1,p+n+1);
sol(0,n);
printf("%lld\n",f[n]);
return 0;
}