分析
根据题目,我们可以写出朴素的状态转移方程
d
p
[
i
]
=
m
i
n
{
d
p
[
j
]
+
(
j
−
i
−
1
+
∑
k
=
j
i
c
[
k
]
−
L
)
2
}
dp[i]=min\{dp[j]+(j-i-1+\sum_{k=j}^ic[k]-L)^2\}
dp[i]=min{dp[j]+(j−i−1+k=j∑ic[k]−L)2}
预处理
c
c
c的前缀和
s
u
m
sum
sum,并使
s
u
m
[
i
]
加
上
i
sum[i]加上i
sum[i]加上i
那么原方程可变为
d
p
[
i
]
=
m
i
n
{
d
p
[
j
]
+
(
(
s
u
m
[
i
]
−
s
u
m
[
j
]
)
−
(
L
+
1
)
)
2
}
dp[i]=min\{dp[j]+((sum[i]-sum[j])-(L+1))^2\}
dp[i]=min{dp[j]+((sum[i]−sum[j])−(L+1))2}
设
k
(
j
<
k
)
k(j<k)
k(j<k)比
j
j
j决策更优,那么
d
p
[
k
]
+
(
(
s
u
m
[
i
]
−
s
u
m
[
k
]
)
−
(
L
+
1
)
)
2
≤
d
p
[
j
]
+
(
(
s
u
m
[
i
]
−
s
u
m
[
j
]
)
−
(
L
+
1
)
)
2
dp[k]+((sum[i]-sum[k])-(L+1))^2\leq dp[j]+((sum[i]-sum[j])-(L+1))^2
dp[k]+((sum[i]−sum[k])−(L+1))2≤dp[j]+((sum[i]−sum[j])−(L+1))2
初步化简得到
d
p
[
k
]
+
a
[
k
]
2
−
2
a
[
i
]
a
[
k
]
+
(
2
L
+
2
)
a
[
k
]
≤
d
p
[
j
]
+
a
[
j
]
2
−
2
a
[
i
]
a
[
j
]
+
(
2
L
+
2
)
a
[
j
]
dp[k]+a[k]^2-2a[i]a[k]+(2L+2)a[k]\leq dp[j]+a[j]^2-2a[i]a[j]+(2L+2)a[j]
dp[k]+a[k]2−2a[i]a[k]+(2L+2)a[k]≤dp[j]+a[j]2−2a[i]a[j]+(2L+2)a[j]
合并得到
d
p
[
k
]
−
d
p
[
j
]
+
a
[
k
]
2
−
a
[
j
]
2
+
(
2
L
+
2
)
(
a
[
k
]
−
a
[
j
]
)
≤
2
a
[
i
]
(
a
[
k
]
−
a
[
j
]
)
dp[k]-dp[j]+a[k]^2-a[j]^2+(2L+2)(a[k]-a[j])\leq 2a[i](a[k]-a[j])
dp[k]−dp[j]+a[k]2−a[j]2+(2L+2)(a[k]−a[j])≤2a[i](a[k]−a[j])
然后就可以清晰地得到
d
p
[
k
]
−
d
p
[
j
]
+
a
[
k
]
2
−
a
[
j
]
2
+
(
2
L
+
2
)
(
a
[
k
]
−
a
[
j
]
)
a
[
k
]
−
a
[
j
]
≤
2
a
[
i
]
\frac{dp[k]-dp[j]+a[k]^2-a[j]^2+(2L+2)(a[k]-a[j])}{a[k]-a[j]}\leq 2a[i]
a[k]−a[j]dp[k]−dp[j]+a[k]2−a[j]2+(2L+2)(a[k]−a[j])≤2a[i]
然而还可以进一步化简得到
d
p
[
k
]
−
d
p
[
j
]
+
a
[
k
]
+
a
[
j
]
a
[
k
]
−
a
[
j
]
≤
2
(
a
[
i
]
−
L
−
1
)
\frac{dp[k]-dp[j]+a[k]+a[j]}{a[k]-a[j]}\leq 2(a[i]-L-1)
a[k]−a[j]dp[k]−dp[j]+a[k]+a[j]≤2(a[i]−L−1)
右边的已知值是单调递增的,所以维护下凸壳,于是
代码
#include <cstdio>
#include <cctype>
#define rr register
#define w(x) ((x)*(x))
using namespace std;
int head=1,tail=1,n,t,q[50001];
long long sum[50001],dp[50001];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline double slope(int x,int y){//计算斜率
if (sum[y]-sum[x]==0) return 1e18;
else return 1.0*(dp[y]-dp[x])/(sum[y]-sum[x])+sum[x]+sum[y];
}
signed main(){
n=iut(); t=iut()+1;
for (rr int i=1;i<=n;++i) sum[i]=sum[i-1]+iut();
for (rr int i=1;i<=n;++i) sum[i]+=i;
for (rr int i=1;i<=n;++i){
while (head<tail&&slope(q[head],q[head+1])<=(sum[i]-t)<<1) ++head;//维护队头
dp[i]=dp[q[head]]+w(sum[i]-sum[q[head]]-t);//dp方程
while (head<tail&&slope(q[tail-1],q[tail])>slope(q[tail],i)) --tail;//维护队尾
q[++tail]=i;
}
return !printf("%lld",dp[n]);
}