写在前面
斜率Dp貌似算是Dp优化中最难之一了吧~~(要不然LOJ干嘛把他放最后)~~
我也是一直处于深沉的懵逼之中,不敢去动它
今天问了一下同寝的Dalao CLY,终于对最简单的斜率Dp有了一丢丢的了解&理解吧
直接到题目里来看吧:
Problem:
给出N个数,分成任意个连续段,每段的价值为
a
∗
S
2
+
b
∗
S
+
c
,
其
中
S
=
∑
X
i
a*S^2+b*S+c,其中S=\sum X_i
a∗S2+b∗S+c,其中S=∑Xi
求最大价值和
N<=
1
0
6
10^6
106,
X
i
X_i
Xi>=0
Solution
考虑原始Dp
F[i]表示前i个的最大价值和
则易得
F
[
i
]
=
m
a
x
(
F
[
j
]
+
v
a
l
(
j
,
i
)
)
F[i]=max(F[j]+val(j,i))
F[i]=max(F[j]+val(j,i))
O
(
N
2
)
O(N^2)
O(N2) 、、、
然后好像毫无办法
重头戏来了!
(貌似也是斜率Dp基本步骤)
我们任取i的前继状态j,k,不妨令j>k
那么j比k优的条件是什么?
F [ j ] + a ∗ ( S [ i ] − S [ j ] ) 2 + b ∗ ( S [ i ] − S [ j ] ) + c > F [ j ] + 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[j]+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[j]+a∗(S[i]−S[k])2+b∗(S[i]−S[k])+c
看不出什么?继续!
F [ j ] + a ∗ ( S [ j ] 2 − 2 ∗ S [ i ] ∗ S [ j ] ) − b ∗ S [ j ] > F [ k ] + a ∗ ( S [ k ] 2 − 2 ∗ S [ i ] ∗ S [ k ] ) − b ∗ S [ k ] F[j]+a*(S[j]^2-2*S[i]*S[j])-b*S[j]>F[k]+a*(S[k]^2-2*S[i]*S[k])-b*S[k] F[j]+a∗(S[j]2−2∗S[i]∗S[j])−b∗S[j]>F[k]+a∗(S[k]2−2∗S[i]∗S[k])−b∗S[k]
由于和i有关的量都可以看成是常量,我们把有i的都移到一边
F [ j ] − F [ k ] + a ∗ S [ j ] 2 − a ∗ S [ k ] 2 − b ∗ S [ j ] − b ∗ S [ k ] > 2 ∗ a ∗ S [ i ] ∗ ( S [ j ] − S [ k ] ) F[j]-F[k]+a*S[j]^2-a*S[k]^2-b*S[j]-b*S[k]>2*a*S[i]*(S[j]-S[k]) F[j]−F[k]+a∗S[j]2−a∗S[k]2−b∗S[j]−b∗S[k]>2∗a∗S[i]∗(S[j]−S[k])
有没有发现左边有点东西,我们把j,k分别整齐排列
( 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])>=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])>=2∗a∗S[i]∗(S[j]−S[k])
设 Y [ x ] = F [ x ] + a ∗ S [ x ] 2 − b ∗ S [ x ] 设Y[x]=F[x]+a*S[x]^2-b*S[x] 设Y[x]=F[x]+a∗S[x]2−b∗S[x],再把S[j]-S[k]除过去
Y [ j ] − Y [ k ] S [ j ] − S [ k ] > = 2 ∗ a ∗ S [ i ] \frac{Y[j]-Y[k]}{S[j]-S[k]}>=2*a*S[i] S[j]−S[k]Y[j]−Y[k]>=2∗a∗S[i]
或者再明显一点~~
Y [ j ] − Y [ k ] X [ j ] − X [ k ] > = 2 ∗ a ∗ S [ i ] \frac{Y[j]-Y[k]}{X[j]-X[k]}>=2*a*S[i] X[j]−X[k]Y[j]−Y[k]>=2∗a∗S[i]
再懂得斜率Dp的意思了吗?左边不就是个斜率吗!!!
因为Xi>=0,所以Si是递增的,即斜率是递增的,那么用一个单调队列维护斜率不就好了吗QWQ
Easy Code
#include<bits/stdc++.h>
#define gt() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
#define pt(ch) (Top<1000000?St[Top++]=ch:(Out(),St[(Top=0)++]=ch))
#define Out() (fwrite(St,1,Top,stdout))
#define LL long long
using namespace std;
int Top;static char St[1000000],buf[1000000],*p1=buf,*p2=buf;
const int maxn=(1e6)+5;
int N,hd,tl,Q[maxn];LL X[maxn],Y[maxn],F[maxn];int a,b,c;
int Re(){
int ret=0;bool f=0;char ch=gt();
while(ch<'0'||ch>'9') f|=(ch=='-'),ch=gt();
while(ch>='0'&&ch<='9') ret=ret*10+(ch^'0'),ch=gt();
return f?-ret:ret;
}
void Wri(int x){if(x<0) x=-x,pt('-');if(x>9) Wri(x/10);pt(x%10+'0');}
#define sqr(x) ((x)*(x))
int main(){
#ifdef hhh
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
#endif
N=Re(),a=Re(),b=Re(),c=Re();
for(int i=1,D;i<=N;i++){
X[i]=X[i-1]+Re();
while(hd<tl&&Y[Q[hd+1]]-Y[Q[hd]]>=a*X[i]*(X[Q[hd+1]]-X[Q[hd]])<<1) hd++;
F[i]=F[Q[hd]]+a*sqr(D=X[i]-X[Q[hd]])+b*D+c,Y[i]=F[i]+a*sqr(X[i])-b*X[i];
while(hd<tl&&(Y[i]-Y[Q[tl]])*(X[Q[tl]]-X[Q[tl-1]])>=(Y[Q[tl]]-Y[Q[tl-1]])*(X[i]-X[Q[tl]])) tl--;
//即(Y[i]-Y[Q[tl]])/(X[i]-X[Q[tl]])>=(Y[Q[tl]]-Y[Q[tl-1]])/(X[Q[tl]]-X[Q[tl-1]])--->ki>kt
Q[++tl]=i;
}
printf("%lld\n",F[N]);
return 0;
}