Analysis
比较裸的斜率优化
1.推出转移方程
定义
f
[
i
]
f[i]
f[i]表示在第i个位置上放守望塔的最小花费
显然最后答案在
f
[
n
]
f[n]
f[n]中
转移方程
f
[
i
]
=
m
i
n
f
[
j
]
+
(
i
−
j
)
∗
(
i
−
j
−
1
)
/
2
+
a
[
i
]
(
j
<
i
)
f[i]=min f[j]+(i-j)*(i-j-1)/2+a[i](j<i)
f[i]=minf[j]+(i−j)∗(i−j−1)/2+a[i](j<i)
2.转化形式,变作
y
=
k
x
∗
b
y=kx*b
y=kx∗b
(y,x只与j有关,k,b只与i有关)
得到
2
∗
f
[
j
]
+
j
2
+
j
=
2
i
∗
j
+
2
∗
f
[
i
]
−
i
2
+
i
−
2
∗
a
[
i
]
2*f[j]+j^2+j=2i*j+2*f[i]-i^2+i-2*a[i]
2∗f[j]+j2+j=2i∗j+2∗f[i]−i2+i−2∗a[i]
然后因为斜率(2*i)和决策(j)都是单调递增的,我们用单调队列维护一个下凸包即可
Code
#include<bits/stdc++.h>
#define in read()
#define re register
#define int long long
using namespace std;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9'){
res=(res<<1)+(res<<3)+(ch^48);
ch=getchar();
}
return f==1?res:-res;
}
typedef long long ll;
const int N=1e6+10;
int n,a[N],q[N];
ll f[N];
inline double slope(int x,int y){
return (double)(2*f[y]+y*y+y-2*f[x]-x*x-x)/(double)(y-x);
}
signed main(){
n=in;
for(re int i=1;i<=n;++i) a[i]=in;
int l=0,r=0;
for(re int i=1;i<=n;++i){
while(l<r&&slope(q[l],q[l+1])<2*i) l++;
f[i]=f[q[l]]+(i-q[l])*1ll*(i-q[l]-1)/2+a[i];
while(l<r&&slope(i,q[r])<slope(q[r],q[r-1])) r--;
q[++r]=i;
}
cout<<f[n];
return 0;
}
Tag
博猪(* ̄(oo) ̄)之慢慢成长篇之模板训练