P4655 [CEOI2017]Building Bridges
P4655 [CEOI2017]Building Bridges
为啥黑题没紫题难啊/kk,感觉这题30天之内会掉紫
状态非常一眼&simple:设 \(dp_i\) 表示 \(1,i\) 联通的最小代价
令 \(s_n=\sum_{i=1}^{n}w_i\)
转移非常一眼&simple:\(dp_i=\min\{dp_j+(h_i-h_j)^2+s_{i-1}-s_j \}(j<i)\)
处理非常一眼&simple:\(dp_i=\min\{dp_j+h_j^2-s_j-2h_ih_j \}+h_i^2+s_{i-1}\)
非常一眼&simple可以想到用李超树维护,把 \(-2h_i\) 当作斜率,\(dp_j+h_j^2-s_j\) 当作 \(y\) 轴截距,全部插到李超树里,就相当于取 \(x=h_i\) 时所有直线的最小值
其实还可以斜率优化,但是那个 \(w_i\) 可能是负数不一定是凸壳,看别人要 cdq 分治,我感觉李超树简单多了,复杂度都是 \(O(n\log n)\),cdq分治写丑点还会变成 \(O(n\log^2n)\)。。。
第一次用 vim
写出黑题呢(其实这是用 vim
写的第二道题)。但是发现调试太累了,尤其是DS,就不用了qwq
没抢到最优解,只有第三,不知道为啥第一名比我快 30ms
,方法都一样,一定是我人傻常数大。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef double db;
#define mkp(x,y) make_pair(x,y)
#define fi first
#define se second
#define pb(x) push_back(x)
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f?x:-x;
}
#define N 100005
#define M 1000005
#define T (M<<2)
#define inf 1000000000000000000ll
int n,h[N],w[N],cnt,C;
LL s[N],dp[N];
int v[T];
pair<int,LL>li[N];
#define val(x,y) (1ll*li[x].fi*y+li[x].se)
#define lc (p<<1)
#define rc (p<<1|1)
void update(int id,int l=1,int r=C,int p=1){
if(!v[p])return v[p]=id,void();
int mid=(l+r)>>1;
LL nol=val(id,l),nor=val(id,r),lal=val(v[p],l),lar=val(v[p],r);
if(nol>=lal&&nor>=lar)return;
if(nol<=lal&&nor<=lar)return v[p]=id,void();
db inter=1.*(li[id].se-li[v[p]].se)/(li[v[p]].fi-li[id].fi);
if(nol<=lal){
if(inter<=mid)update(id,l,mid,lc);
else update(v[p],mid+1,r,rc),v[p]=id;
}else{
if(inter>mid)update(id,mid+1,r,rc);
else update(v[p],l,mid,lc),v[p]=id;
}
}
LL query(int X,int l=1,int r=C,int p=1){
LL res=inf;
if(v[p])res=min(res,val(v[p],X));
if(l==r)return res;
int mid=(l+r)>>1;
if(X<=mid)res=min(res,query(X,l,mid,lc));
else res=min(res,query(X,mid+1,r,rc));
return res;
}
signed main(){
n=read();
for(int i=1;i<=n;++i)C=max(C,h[i]=read());
for(int i=1;i<=n;++i)w[i]=read(),s[i]=s[i-1]+w[i];
for(int i=1;i<=n;++i){
if(i==1)dp[i]=0;
else dp[i]=query(h[i])+1ll*h[i]*h[i]+s[i-1];
li[++cnt]=mkp(-2*h[i],dp[i]-s[i]+1ll*h[i]*h[i]);
update(cnt);
}
printf("%lld\n",dp[n]);
return 0;
}
路漫漫其修远兮,吾将上下而求索