题目
思路
来纪中第一题,献给斜率优化dp大法,dpnb!!!
论与wyc和xjq住在一个宿舍是什么感受
本题解也许会详细一点
实际上本题属于一个计算几何题……
先来个暴力方程,设
S
i
=
∑
j
=
1
i
(
C
i
+
1
)
S_i=\sum_{j=1}^i(C_i+1)
Si=∑j=1i(Ci+1),又设
f
i
f_i
fi为前i个中的最优解,则有:
f
i
=
m
i
n
(
f
j
+
(
S
i
−
S
j
−
1
−
L
)
2
)
(
1
<
=
j
<
i
)
f_i=min(f_j+(S_i-S_j-1-L)^2)(1<=j<i)
fi=min(fj+(Si−Sj−1−L)2)(1<=j<i)
n方暴力,T到飞起
显然这范围只允许nlogn及以内时间复杂度算法,dp显然在与数据结构没关系的前提下和log也是没关系的,而输入就O(n)了,所以我们的dp算法是O(n)的。
O(n)dp=单调队列优化
单调队列优化+方程中的乘法运算=斜率优化
于是到了美丽的式子时间:
设
j
1
,
j
2
(
1
<
=
j
1
<
j
2
<
i
)
j_1,j_2(1<=j1<j2<i)
j1,j2(1<=j1<j2<i)为2个决策点,若
j
2
j_2
j2优于
j
1
j_1
j1,当且仅当:
f
j
2
−
2
S
i
S
j
2
+
(
S
j
2
+
L
)
2
<
=
f
j
1
−
2
S
i
S
j
1
+
(
S
j
1
+
L
)
2
f_{j_2}-2S_iS_{j_2}+(S_{j_2}+L)^2<=f_{j_1}-2S_iS_{j_1}+(S_{j_1}+L)^2
fj2−2SiSj2+(Sj2+L)2<=fj1−2SiSj1+(Sj1+L)2
移项得:
−
2
S
i
(
S
j
2
−
S
j
1
)
<
=
f
j
1
−
f
j
2
+
(
S
j
1
+
L
)
2
−
(
S
j
2
+
L
)
2
-2S_i(S_{j_2}-S_{j_1})<=f_{j_1}-f_{j_2}+(S_{j_1}+L)^2-(S_{j_2}+L)^2
−2Si(Sj2−Sj1)<=fj1−fj2+(Sj1+L)2−(Sj2+L)2
显然
S
j
2
−
S
j
1
>
0
S_{j_2}-S_{j_1}>0
Sj2−Sj1>0,所以有:
2
S
i
>
=
(
f
j
1
+
(
S
j
1
+
L
)
2
)
−
(
f
j
2
+
(
S
j
2
+
L
)
2
)
S
j
2
−
S
j
−
1
2S_i>={{(f_{j_1}+(S_{j_1}+L)^2)-(f_{j_2}+(S_{j_2}+L)^2)}\over{S_{j_2}-S_{j-1}}}
2Si>=Sj2−Sj−1(fj1+(Sj1+L)2)−(fj2+(Sj2+L)2)
斜率方程构造完成,本题解决
code:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
long long n,L,q[50004],f[50004],x,s[50004],h=1,t=1;
long long Y(int x)
{
return f[x]+(s[x]+L)*(s[x]+L);
}
long long X(int x)
{
return s[x];
}
long double u(int x,int y)
{
return (long double)(Y(y)-Y(x))/(X(y)-X(x));
}
int main()
{
scanf("%lld%lld",&n,&L);
++L;
for (int i=1;i<=n;i++)
{
scanf("%lld",&x);
s[i]=s[i-1]+x+1;
}
for (int i=1;i<=n;i++)
{
while (h<t&&u(q[h],q[h+1])<2*s[i]) h++;
f[i]=f[q[h]]+(s[i]-s[q[h]]-L)*(s[i]-s[q[h]]-L);
while (h<t&&u(q[t-1],i)<u(q[t-1],q[t])) t--;
q[++t]=i;
}
printf("%lld\n",f[n]);
return 0;
}