题面描述
思路
状态转移方程
应该很好想:
设 s s s为战斗力前缀和,那么有
F i = max ( F j + a ∗ ( s i − s j ) 2 + b ∗ ( s i − s j ) + c ) F_i=\max(F_j+a*(s_i-s_j)^2+b*(s_i-s_j)+c) Fi=max(Fj+a∗(si−sj)2+b∗(si−sj)+c)
决策单调性
设有
F
k
+
a
∗
(
s
i
−
s
k
)
2
+
b
∗
(
s
i
−
s
k
)
+
c
≥
F
j
+
a
∗
(
s
i
−
s
j
)
2
+
b
∗
(
s
i
−
s
j
)
+
c
F_k+a*(s_i-s_k)^2+b*(s_i-s_k)+c\ge F_j+a*(s_i-s_j)^2+b*(s_i-s_j)+c
Fk+a∗(si−sk)2+b∗(si−sk)+c≥Fj+a∗(si−sj)2+b∗(si−sj)+c
化简为
F k − 2 ∗ a ∗ s i ∗ s k + a ∗ s k 2 − b ∗ s k ≥ F j − 2 ∗ a ∗ s i ∗ s j + a ∗ s j 2 − b ∗ s j F_k-2*a*s_i*s_k+a*{s_k}^2-b*s_k\ge F_j-2*a*s_i*s_j+a*{s_j}^2-b*s_j Fk−2∗a∗si∗sk+a∗sk2−b∗sk≥Fj−2∗a∗si∗sj+a∗sj2−b∗sj
对于未来状态 t t t,证明:
F k + a ∗ ( s t − s k ) 2 + b ∗ ( s t − s k ) + c ≥ F j + a ∗ ( s t − s j ) 2 + b ∗ ( s t − s j ) + c F_k+a*(s_t-s_k)^2+b*(s_t-s_k)+c\ge F_j+a*(s_t-s_j)^2+b*(s_t-s_j)+c Fk+a∗(st−sk)2+b∗(st−sk)+c≥Fj+a∗(st−sj)2+b∗(st−sj)+c
化简为
F k − 2 ∗ a ∗ s t ∗ s k + a ∗ s k 2 − b ∗ s k ≥ F j − 2 ∗ a ∗ s t ∗ s j + a ∗ s j 2 − b ∗ s j F_k-2*a*s_t*s_k+a*{s_k}^2-b*s_k\ge F_j-2*a*s_t*s_j+a*{s_j}^2-b*s_j Fk−2∗a∗st∗sk+a∗sk2−b∗sk≥Fj−2∗a∗st∗sj+a∗sj2−b∗sj
由于 s t = s i + v a l s_t=s_i+val st=si+val,则
F k − 2 ∗ a ∗ ( s i + v a l ) ∗ s k + a ∗ s k 2 − b ∗ s k ≥ F j − 2 ∗ a ∗ ( s i + v a l ) ∗ s j + a ∗ s j 2 − b ∗ s j F_k-2*a*(s_i+val)*s_k+a*{s_k}^2-b*s_k\ge F_j-2*a*(s_i+val)*s_j+a*{s_j}^2-b*s_j Fk−2∗a∗(si+val)∗sk+a∗sk2−b∗sk≥Fj−2∗a∗(si+val)∗sj+a∗sj2−b∗sj
根据
F k − 2 ∗ a ∗ s i ∗ s k + a ∗ s k 2 − b ∗ s k ≥ F j − 2 ∗ a ∗ s i ∗ s j + a ∗ s j 2 − b ∗ s j F_k-2*a*s_i*s_k+a*{s_k}^2-b*s_k\ge F_j-2*a*s_i*s_j+a*{s_j}^2-b*s_j Fk−2∗a∗si∗sk+a∗sk2−b∗sk≥Fj−2∗a∗si∗sj+a∗sj2−b∗sj
只需要证明
− 2 ∗ a ∗ v a l ∗ s k ≥ − 2 ∗ a ∗ v a l ∗ s j -2*a*val*s_k\ge-2*a*val*s_j −2∗a∗val∗sk≥−2∗a∗val∗sj
由于 a < 0 , v a l > 0 , s k > s j a<0,val>0,s_k>s_j a<0,val>0,sk>sj,可知:
v a l ∗ s k ≥ v a l ∗ s j val*s_k\ge val*s_j val∗sk≥val∗sj
证毕。
踢队头
根据上文,
F k − 2 ∗ a ∗ s i ∗ s k + a ∗ s k 2 − b ∗ s k ≥ F j − 2 ∗ a ∗ s i ∗ s j + a ∗ s j 2 − b ∗ s j ( k > j ) F_k-2*a*s_i*s_k+a*{s_k}^2-b*s_k\ge F_j-2*a*s_i*s_j+a*{s_j}^2-b*s_j(k>j) Fk−2∗a∗si∗sk+a∗sk2−b∗sk≥Fj−2∗a∗si∗sj+a∗sj2−b∗sj(k>j)
F j − F k + a ∗ s j 2 − a ∗ s k 2 − b ∗ s j + b ∗ s k ≤ 2 ∗ a ∗ s i ∗ s j − 2 ∗ a ∗ s i ∗ s k F_j-F_k+a*{s_j}^2-a*{s_k}^2-b*s_j+b*s_k\le 2*a*s_i*s_j-2*a*s_i*s_k Fj−Fk+a∗sj2−a∗sk2−b∗sj+b∗sk≤2∗a∗si∗sj−2∗a∗si∗sk
( F j + a ∗ s j 2 − b ∗ s j ) − ( F k + a ∗ s k 2 − b ∗ s k ) ≤ 2 ∗ a ∗ s i ∗ ( s j − s k ) (F_j+a*{s_j}^2-b*s_j)-(F_k+a*{s_k}^2-b*s_k)\le 2*a*s_i*(s_j-s_k) (Fj+a∗sj2−b∗sj)−(Fk+a∗sk2−b∗sk)≤2∗a∗si∗(sj−sk)
由于 s j − s k < 0 , a < 0 s_j-s_k<0,a<0 sj−sk<0,a<0,所以
c a l c ( j , k ) = ( F j + a ∗ s j 2 − b ∗ s j ) − ( F k + a ∗ s k 2 − b ∗ s k ) a ∗ ( s j − s k ) ≤ 2 ∗ s i calc(j,k)=\frac{(F_j+a*{s_j}^2-b*s_j)-(F_k+a*{s_k}^2-b*s_k)}{a*(s_j-s_k)}\le2*s_i calc(j,k)=a∗(sj−sk)(Fj+a∗sj2−b∗sj)−(Fk+a∗sk2−b∗sk)≤2∗si
当 c a l c ( j , k ) ≤ 2 ∗ s i calc(j,k)\le 2*s_i calc(j,k)≤2∗si时, k k k优于 j j j.
因此当 c a l c ( q h e a d , q h e a d + 1 ) ≤ 2 ∗ s i calc(q_{head},q_{head+1})\le 2*s_i calc(qhead,qhead+1)≤2∗si
h e a d + 1 head+1 head+1优于 h e a d head head。
由于 s i s_i si随 i i i增大而增大,那么 c a l c ( q h e a d , q h e a d + 1 ) calc(q_{head},q_{head+1}) calc(qhead,qhead+1)随 h e a d head head增大而增大,才符合 h e a d head head为最优解,因此斜率是不断递增的。
踢队尾
根据斜率是不断递增的,仅当
c a l c ( q t a i l , i ) ≥ c a l c ( q t a i l − 1 , q t a i l ) calc(q_{tail},i)\ge calc(q_{tail-1},q_{tail}) calc(qtail,i)≥calc(qtail−1,qtail)
斜率才满足不断递增。
故当
c a l c ( q t a i l , i ) ≤ c a l c ( q t a i l − 1 , q t a i l ) calc(q_{tail},i)\le calc(q_{tail-1},q_{tail}) calc(qtail,i)≤calc(qtail−1,qtail)
删去队尾。
AC code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define gc getchar()
#define ll long long
using namespace std;
const int N=1e6+10;
inline void qr(ll &x)
{
x=0;int f=1;char c=gc;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
x*=f;
}
inline void qw(ll x)
{
if(x<0)x=-x,putchar('-');
if(x/10)qw(x/10);
putchar(x%10+48);
}
ll s[N],a,b,c,f[N];
int q[N],l,r;
inline double calc(int j,int k)
{
return ((f[j]+a*s[j]*s[j]-b*s[j])-(f[k]+a*s[k]*s[k]-b*s[k]))/(double)(a*(s[j]-s[k]));
}
int main()
{
int n;scanf("%d",&n);
qr(a),qr(b),qr(c);
for(int i=1;i<=n;i++)qr(s[i]),s[i]+=s[i-1];
l=1;r=1;q[1]=0;
for(int i=1;i<=n;i++)
{
while(l<r&&calc(q[l],q[l+1])<=2.0*s[i])++l;
f[i]=f[q[l]]+a*(s[i]-s[q[l]])*(s[i]-s[q[l]])+b*(s[i]-s[q[l]])+c;
while(l<r&&calc(q[r],i)<=calc(q[r-1],q[r]))--r;
q[++r]=i;
}
qw(f[n]);puts("");
return 0;
}