Statement
[P4655 CEOI2017]Building Bridges - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
Solution
斜率优化DP+李超线段树
考虑设 \(f[i]\) 表示链接到 \(i\) 的最小代价,那么有:
\[f[i]=\min_{j<i}\{f[j]+(h_i-h_j)^2+sw[i-1]-sw[j]\} \]这个是 \(O(n^2)\) 的,需要优化
看到这个平方项,充满了斜率优化的味道,我们考虑移项
\[f[i]=h_i^2+sw[i-1]+\min_{j<i}\{-2h_ih_j+h_j^2+f[j]-sw[j]\} \]我们可以看作一条斜率为 \(-2h_j\) ,截距为 \(h_j^2+f[j]-sw[j]\) 的直线
我们考虑用李超线段树维护这些直线,对于一个 \(i\) ,只需要求出当 \(x=h_i\) 时最小值就可以了
这样就是 \(O(n\log n)\)
Code
#include<bits/stdc++.h>
#define int long long
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
const int N = 1e5+5;
const int M = 1e6+5;
int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
return s*w;
}
struct Line{int k,b;}line[N];
int t[M<<2],h[N],w[N],sw[N],f[N];
int n;
int calc(int x,int id){return x*line[id].k+line[id].b;}
void insert(int l,int r,int rt,int u){
if(l==r)return (calc(l,t[rt])>calc(l,u)&&(t[rt]=u,1)),void();//
int mid=(l+r)>>1;
if(calc(mid,t[rt])>calc(mid,u))swap(t[rt],u);//
if(calc(l,u)<calc(l,t[rt]))insert(l,mid,ls,u);//
else if(calc(r,u)<calc(r,t[rt]))insert(mid+1,r,rs,u);//
}
int query(int l,int r,int rt,int u){//
if(l==r)return calc(l,t[rt]);
int mid=(l+r)>>1,tmp=calc(u,t[rt]);
if(u<=mid)return min(tmp,query(l,mid,ls,u));
else return min(tmp,query(mid+1,r,rs,u));
}
signed main(){
n=read(),line[0]={0,(int)1e18};
for(int i=1;i<=n;++i)h[i]=read();
for(int i=1;i<=n;++i)w[i]=read(),sw[i]=sw[i-1]+w[i];
line[1]={-2*h[1],h[1]*h[1]-sw[1]},insert(0,M,1,1);
for(int i=2;i<=n;++i){
f[i]=query(0,M,1,h[i])+h[i]*h[i]+sw[i-1];
line[i]={-2*h[i],h[i]*h[i]+f[i]-sw[i]},insert(0,M,1,i);
}
printf("%lld\n",f[n]);
return 0;
}