题目大意: 有 n n n 个物品,你可以对一段连续的物品进行压缩,假如压缩区间 [ l , r ] [l,r] [l,r],那么费用为: ( r − l + ∑ i = l r a [ i ] − L ) 2 (r-l+\sum_{i=l}^r a[i]-L)^2 (r−l+∑i=lra[i]−L)2,问将这 n n n 个物品压缩的最小费用。
题解
设
f
[
i
]
f[i]
f[i] 表示将前
i
i
i 个物品压缩的最小费用,
c
[
i
]
=
∑
j
=
1
i
a
[
j
]
c[i]=\sum_{j=1}^i a[j]
c[i]=∑j=1ia[j],那么有:
f
[
i
]
=
min
j
=
0
i
−
1
{
f
[
j
]
+
(
i
−
j
−
1
+
c
[
i
]
−
c
[
j
]
−
L
)
2
}
f[i]=\min_{j=0}^{i-1} \{f[j]+(i-j-1+c[i]-c[j]-L)^2\}
f[i]=j=0mini−1{f[j]+(i−j−1+c[i]−c[j]−L)2}
显然要用斜率优化去搞了,那么接下来就是推柿子了(这种柿子建议自己手推一下,虽然很繁琐,但是获得的成就感以及收获还是很大的):
假如用
j
j
j 来更新
i
i
i 比用
k
k
k 来更新
i
i
i 更优,那么需要满足:
f
[
j
]
+
(
i
−
j
−
1
+
c
[
i
]
−
c
[
j
]
−
L
)
2
<
f
[
k
]
+
(
i
−
k
−
1
+
c
[
i
]
−
c
[
k
]
−
L
)
2
f[j]+(i-j-1+c[i]-c[j]-L)^2<f[k]+(i-k-1+c[i]-c[k]-L)^2
f[j]+(i−j−1+c[i]−c[j]−L)2<f[k]+(i−k−1+c[i]−c[k]−L)2
设
g
[
i
]
=
i
+
c
[
i
]
g[i]=i+c[i]
g[i]=i+c[i],代入得:
f
[
j
]
+
(
g
[
i
]
−
g
[
j
]
−
1
−
L
)
2
<
f
[
k
]
+
(
g
[
i
]
−
g
[
k
]
−
1
−
L
)
2
f[j]+(g[i]-g[j]-1-L)^2<f[k]+(g[i]-g[k]-1-L)^2
f[j]+(g[i]−g[j]−1−L)2<f[k]+(g[i]−g[k]−1−L)2
为了保护各位的眼睛,建议跳过这一段,拆开得:
f
[
j
]
+
g
[
i
]
2
−
g
[
i
]
g
[
j
]
−
g
[
i
]
−
g
[
i
]
L
−
g
[
i
]
g
[
j
]
+
g
[
j
]
2
+
g
[
j
]
+
g
[
j
]
L
−
g
[
i
]
+
g
[
j
]
+
1
+
L
−
g
[
i
]
L
+
g
[
j
]
L
+
L
+
L
2
<
f
[
k
]
+
g
[
i
]
2
−
g
[
i
]
g
[
k
]
−
g
[
i
]
−
g
[
i
]
L
−
g
[
i
]
g
[
k
]
+
g
[
k
]
2
+
g
[
k
]
+
g
[
k
]
L
−
g
[
i
]
+
g
[
k
]
+
1
+
L
−
g
[
i
]
L
+
g
[
k
]
L
+
L
+
L
2
f[j]+g[i]^2-g[i]g[j]-g[i]-g[i]L-g[i]g[j]+g[j]^2+g[j]+g[j]L-\\ g[i]+g[j]+1+L-g[i]L+g[j]L+L+L^2<\\ f[k]+g[i]^2-g[i]g[k]-g[i]-g[i]L-g[i]g[k]+g[k]^2+g[k]+g[k]L-\\ g[i]+g[k]+1+L-g[i]L+g[k]L+L+L^2
f[j]+g[i]2−g[i]g[j]−g[i]−g[i]L−g[i]g[j]+g[j]2+g[j]+g[j]L−g[i]+g[j]+1+L−g[i]L+g[j]L+L+L2<f[k]+g[i]2−g[i]g[k]−g[i]−g[i]L−g[i]g[k]+g[k]2+g[k]+g[k]L−g[i]+g[k]+1+L−g[i]L+g[k]L+L+L2
f [ j ] − g [ i ] g [ j ] − g [ i ] g [ j ] + g [ j ] 2 + g [ j ] + g [ j ] L + g [ j ] + g [ j ] L < f [ k ] − g [ i ] g [ k ] − g [ i ] g [ k ] + g [ k ] 2 + g [ k ] + g [ k ] L + g [ k ] + g [ k ] L f[j]-g[i]g[j]-g[i]g[j]+g[j]^2+g[j]+g[j]L+g[j]+g[j]L<\\ f[k]-g[i]g[k]-g[i]g[k]+g[k]^2+g[k]+g[k]L+g[k]+g[k]L f[j]−g[i]g[j]−g[i]g[j]+g[j]2+g[j]+g[j]L+g[j]+g[j]L<f[k]−g[i]g[k]−g[i]g[k]+g[k]2+g[k]+g[k]L+g[k]+g[k]L
f [ j ] − f [ k ] < 2 g [ i ] ( g [ j ] − g [ k ] ) + g [ k ] 2 + 2 g [ k ] − g [ j ] 2 − 2 g [ j ] + 2 L ( g [ k ] − g [ j ] ) f[j]-f[k]<2g[i](g[j]-g[k])+g[k]^2+2g[k]-g[j]^2-2g[j]+2L(g[k]-g[j]) f[j]−f[k]<2g[i](g[j]−g[k])+g[k]2+2g[k]−g[j]2−2g[j]+2L(g[k]−g[j])
f [ j ] − f [ k ] < 2 ( g [ i ] − L − 1 ) ( g [ j ] − g [ k ] ) + g [ k ] 2 − g [ j ] 2 f[j]-f[k]<2(g[i]-L-1)(g[j]-g[k])+g[k]^2-g[j]^2 f[j]−f[k]<2(g[i]−L−1)(g[j]−g[k])+g[k]2−g[j]2
f [ j ] − f [ k ] + g [ j ] 2 − g [ k ] 2 g [ j ] − g [ k ] < 2 ( g [ i ] − L − 1 ) \frac {f[j]-f[k]+g[j]^2-g[k]^2} {g[j]-g[k]}<2(g[i]-L-1) g[j]−g[k]f[j]−f[k]+g[j]2−g[k]2<2(g[i]−L−1)
设
T
[
i
]
=
f
[
i
]
+
g
[
i
]
2
T[i]=f[i]+g[i]^2
T[i]=f[i]+g[i]2,代入得:
T
[
j
]
−
T
[
k
]
g
[
j
]
−
g
[
k
]
<
2
(
g
[
i
]
−
L
−
1
)
\frac {T[j]-T[k]} {g[j]-g[k]} < 2(g[i]-L-1)
g[j]−g[k]T[j]−T[k]<2(g[i]−L−1)
于是变成了一个斜率的形式了!那么斜率优化直接跑。
因为右边的 2 ( g [ i ] − L − 1 ) 2(g[i]-L-1) 2(g[i]−L−1) 具有单调性,所以可以用单调队列。
为了避免精度问题,我把上面的柿子中左边的除数移到了右边,这样就避免了浮点数运算。
代码如下:
#include <cstdio>
#include <cstring>
#define ll long long
#define maxn 50010
int n,L;
ll c[maxn],f[maxn],g[maxn],T[maxn];
int q[maxn],st=1,ed=1;
inline ll up(int x,int y){return T[x]-T[y];}
inline ll down(int x,int y){return g[x]-g[y];}
inline ll calc(int x,int now){return f[x]+(now-x-1+c[now]-c[x]-L)*(now-x-1+c[now]-c[x]-L);}
int main()
{
scanf("%d %d",&n,&L);
for(int i=1;i<=n;i++)
scanf("%lld",&c[i]),c[i]+=c[i-1];
q[st]=0;f[0]=0;
for(int i=1;i<=n;i++)
{
g[i]=i+c[i];//注意g[i]的计算不能放到下面
while(st<ed&&up(q[st+1],q[st])<2ll*(g[i]-(ll)L-1ll)*down(q[st+1],q[st]))st++;
f[i]=calc(q[st],i); T[i]=f[i]+g[i]*g[i];
while(st<ed&&up(i,q[ed])*down(q[ed],q[ed-1])<up(q[ed],q[ed-1])*down(i,q[ed]))ed--;
q[++ed]=i;
}
printf("%lld",f[n]);
}