正题
题目链接:https://www.luogu.com.cn/problem/P4655
题目大意
nnn座桥,删除第iii座会产生wiw_iwi的代价,相邻的两座桥i,ji,ji,j会产生(hi−hj)2(h_i-h_j)^2(hi−hj)2的代价,要求代价最小。
解题思路
设fif_ifi表示留到第iii座桥的答案,si=∑j=1iwis_i=\sum_{j=1}^iw_isi=∑j=1iwi,那么有fi=fj+si−1−sj+(hi−hj)2f_i=f_j+s_{i-1}-s_j+(h_i-h_j)^2fi=fj+si−1−sj+(hi−hj)2
fi=si−1+hi2+fj−sj+hj2−2hihjf_i=s_{i-1}+h_i^2+f_j-s_j+h_j^2-2h_ih_jfi=si−1+hi2+fj−sj+hj2−2hihj
其实就是要求最小化fj−sj+hj2−2hihjf_j-s_j+h_j^2-2h_ih_jfj−sj+hj2−2hihj
设Si=fi−si+hi2S_i=f_i-s_i+h_i^2Si=fi−si+hi2
那么就有fi−si−1−hi2=Sj−2hihjf_i-s_{i-1}-h_i^2=S_j-2h_ih_jfi−si−1−hi2=Sj−2hihj
然后上CDQCDQCDQ斜率优化就好了,大体是左边排序后处理出左边的凸壳然后考虑它对右边的贡献即可,注意对于hjh_jhj相等的我们取SjS_jSj小的点。
时间复杂度O(nlog2n)O(n\log^2 n)O(nlog2n)(同理用归并排序可以做到O(nlogn)O(n\log n)O(nlogn))
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1e5+10;
ll n,p[N],s[N],f[N],S[N],h[N],st[N],q[N];
bool cmp(ll a,ll b){return h[a]>h[b];}
bool cMp(ll a,ll b){return (h[a]==h[b])?(S[a]<S[b]):(h[a]<h[b]);}
double slope(ll a,ll b)
{return (double)(S[a]-S[b])/(h[a]-h[b]);}
void cdq(ll l,ll r){if(l==r){S[l]=f[l]-s[l]+h[l]*h[l];return;}ll mid=(l+r)>>1,cnt1=l-1,cnt2=mid;for(ll i=l;i<=r;i++)if(p[i]<=mid)q[++cnt1]=p[i];else q[++cnt2]=p[i];for(ll i=l;i<=r;i++)p[i]=q[i];cdq(l,mid);ll tot=0;for(ll i=l;i<=mid;i++){if(h[p[i]]==h[p[i-1]]&&i!=l)continue;while(tot>1&&slope(st[tot-1],st[tot])>slope(st[tot-1],p[i]))tot--;st[++tot]=p[i];}for(ll i=mid+1;i<=r;i++){while(tot>1&&slope(st[tot-1],st[tot])>2*h[p[i]])tot--;f[p[i]]=min(f[p[i]],s[p[i]-1]+h[p[i]]*h[p[i]]+S[st[tot]]-2*h[p[i]]*h[st[tot]]);}cdq(mid+1,r);sort(p+l,p+r+1,cMp);return;
}
int main()
{memset(f,0x3f,sizeof(f));scanf("%lld",&n);f[1]=0;for(ll i=1;i<=n;i++)scanf("%lld",&h[i]),p[i]=i;for(ll i=1;i<=n;i++)scanf("%lld",&s[i]),s[i]+=s[i-1];sort(p+1,p+1+n,cmp);cdq(1,n); printf("%lld",f[n]);return 0;
}