题意:
题解:
洛谷的题解就写的蛮好,首先对于斜率优化,先将它的转移方程写出来,然后对于只包含i的设为A,只包含j的设为B,然后对于含有A和B的项就是二元一次方程中的k和x
这个就可以转成下面的这个式子:
d
p
[
i
]
=
m
i
n
(
d
p
[
j
]
+
(
s
u
m
[
i
]
+
i
−
s
u
m
[
j
]
−
j
−
L
−
1
)
2
)
dp[i]=min(dp[j]+(sum[i]+i−sum[j]−j−L−1)^2)
dp[i]=min(dp[j]+(sum[i]+i−sum[j]−j−L−1)2)
然后sum[i]+i就是A
sum[j]+j+L+1就是B
转换式子变成
d
p
[
i
]
=
d
p
[
j
]
+
A
2
−
2
A
B
+
B
2
dp[i]=dp[j]+A^2-2AB+B^2
dp[i]=dp[j]+A2−2AB+B2
2AB就是k*x
对于这个函数来说,定量就是k,b变量就是x,y。那么对于当前位置来说,i是定量,已经知道了,j则是未知量
所以函数变成
d
p
[
j
]
−
B
2
=
2
A
B
+
d
p
[
i
]
−
A
2
dp[j]-B^2=2AB+dp[i]-A^2
dp[j]−B2=2AB+dp[i]−A2
二元一次方程组的通项是:y=kx+b,那么对于这个方程来说
y
:
d
p
[
j
]
−
B
2
y:dp[j]-B^2
y:dp[j]−B2
k
:
2
A
k:2A
k:2A
x
:
B
x:B
x:B
b
:
d
p
[
i
]
−
A
2
b:dp[i]-A^2
b:dp[i]−A2
然后由于2A是递增的,那么斜率也就是增长的。对于增长的斜率优化来说,最优的点就是队首这个点,如果sta和sta+1的斜率小于k了,那么后面的点一定比前面点更优。对于队尾的话,如果当前点i和en的斜率小于en和en-1的斜率,那么无论k是怎么样的,en都不是最优的,于是将en删除
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=5e4+5;
ll dp[N],sum[N],L,A[N],B[N];
int st[N];
ll X(int i){return B[i];}
ll Y(int i){return dp[i]+B[i]*B[i];}
int main()
{
int n;
scanf("%d%lld",&n,&L);
for(int i=1;i<=n;i++){
scanf("%lld",&sum[i]),sum[i]+=sum[i-1];
A[i]=sum[i]+i;
B[i]=sum[i]+i+L+1;
}
B[0]=L+1;
int sta=0,en=0;
for(int i=1;i<=n;i++){
while(sta<en&&Y(st[sta+1])-Y(st[sta])<2*A[i]*(X(st[sta+1])-X(st[sta])))sta++;
dp[i]=dp[st[sta]]+(A[i]-B[st[sta]])*(A[i]-B[st[sta]]);
while(sta<en&&(Y(i)-Y(st[en]))*(X(st[en])-X(st[en-1]))<(Y(st[en])-Y(st[en-1]))*(X(i)-X(st[en])))en--;
st[++en]=i;
}
printf("%lld\n",dp[n]);
return 0;
}