题目大意
有n个物品,每个物品有一个长度,现需将其分成若干组,每组内编号必须是连续的,将i~j分为一组的长度是
,
费用为,其中L为给定常量。求最小费用。
分析
看到题目,想也没想就敲了一个时间,空间的暴力Dp,为合并区间的最小费用,则
当然过不了。。。
仔细一想,第一维可以省略,表示前个物品合并的最小费用,则
将时间和空间都降了一个数量级,但对于的数据范围,的复杂度还是不够。考虑Dp优化。
注意到方程中有与有关的乘积项,考虑斜率优化。
令,则方程可化为
若存在且在j处比在k处取值更优,则有下面的不等式
解得
这说明若上式成立,则j处优于k处。
然后就可以维护一个单调队列,使得能在的时间内解决。具体见代码。
代码
#include <bits/stdc++.h>
using namespace std;
#define p(x) ((x)*(x))
int n,L;
long long a[50005],g[50005];
long long f[50005],c;
int q[50005];
int head,tail;
double calc(int k,int j) {
return ((f[j]+p(g[j])+2.0*c*g[j])-(f[k]+p(g[k])+2.0*c*g[k]))/(2.0*(g[j]-g[k]));
}
int main() {
scanf("%d%d",&n,&L);
c=L+1;
for (int i=1;i<=n;i++)
scanf("%lld",&g[i]),g[i]+=g[i-1];
for (int i=1;i<=n;i++)
g[i]+=i;
head=1;
tail=0;
q[++tail]=0;
for (int i=1;i<=n;i++) {
while (head<tail&&calc(q[head],q[head+1])<=g[i]) head++;
//由于推出的不等式
//若calc(q[head],q[head+1])<=g[i],说明head+1,比head更优,直接出队
int t=q[head];
f[i]=f[t]+p(g[i]-g[t]-c);
while (head<tail&&calc(q[tail],i)<calc(q[tail-1],q[tail])) tail--;
q[++tail]=i;
}
printf("%lld",f[n]);
return 0;
}