给出N个柱子,现在要顺次连接它们(从1连到N),每次连接的代价为高度之差的平方。
如果某些柱子不连,那么需要用Wi的代价销毁它。
求最小代价。
神奇的链接(一个叫陈万洲的抄袭狗的博客) ↓ https://www.yunyii.cn/article/Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDU0MDY5L2FydGljbGUvZGV0YWlscy84MzM4MTk5Mg==
很显然的DP 很显然的斜率优化
推出来一坨东西后,发现需要满足的斜率 ( 2 × h i ) (2\times h_i) (2×hi)不是单调的。
所以。。。CDQ分治啊。。。
先按 h i h_i hi升序排列。
在处理 [ l , r ] [l,r] [l,r]区间时,先按照编号,分为较小的较大的两部分。(因为只有编号较小的会对编号较大的做出贡献)
然后先处理小的部分,把小的部分的DP值算出来。
然后再通过小的部分来更新大的部分的答案。
然后再处理右半部分。
当然,返回的时候不能忘了把顺序还原为按h值升序
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define SF scanf #define PF printf #define MAXN 100010 using namespace std; typedef long long ll; struct node{ ll x,y,id; }p[MAXN],tmp[MAXN]; int q[MAXN]; ll dp[MAXN],h[MAXN],w[MAXN],pre[MAXN]; int n; bool sort_by_x(const node &a,const node &b){ if(a.x!=b.x) return a.x<b.x; return a.id<b.id; } void CDQ(int l,int r){ // PF("{%d %d}\n",l,r); // for(int i=1;i<=n;i++) // PF("[%lld %lld %lld %lld]\n",p[i].x,p[i].id,p[i].y,dp[p[i].id]); // PF("-------------------\n"); if(l==r){ p[l].y=dp[l]+h[l]*h[l]-pre[l]; return ; } int mid=(l+r)>>1; int xl=l,xr=mid+1; for(int i=l;i<=r;i++){ if(p[i].id<=mid) tmp[xl++]=p[i]; else tmp[xr++]=p[i]; } for(int i=l;i<=r;i++) p[i]=tmp[i]; CDQ(l,mid); int head=1,tail=0; for(int i=l;i<=mid;i++){ while(head<tail&&1.0*(p[i].y-p[q[tail]].y)*(1.0*(p[q[tail]].x-p[q[tail-1]].x))<=1.0*(p[q[tail]].y-p[q[tail-1]].y)*(1.0*(p[i].x-p[q[tail]].x))) tail--; q[++tail]=i; } for(int id=mid+1;id<=r;id++){ int i=p[id].id; while(head<tail&&1.0*(p[q[head+1]].y-p[q[head]].y)<=2.0*h[i]*(1.0*(p[q[head+1]].x-p[q[head]].x))) head++; int j=p[q[head]].id; dp[i]=min(dp[i],dp[j]+(h[i]-h[j])*(h[i]-h[j])+pre[i-1]-pre[j]); } CDQ(mid+1,r); xl=l,xr=mid+1; for(int i=l;i<=r;i++){ if(xr>r||(xl<=mid&&p[xl].x<p[xr].x)) tmp[i]=p[xl++]; else tmp[i]=p[xr++]; } for(int i=l;i<=r;i++) p[i]=tmp[i]; } int main(){ memset(dp,0x3f,sizeof dp); SF("%d",&n); for(int i=1;i<=n;i++) SF("%lld",&h[i]); for(int i=1;i<=n;i++){ SF("%lld",&w[i]); pre[i]=pre[i-1]+w[i]; } for(int i=1;i<=n;i++){ p[i].id=i; p[i].x=h[i]; } sort(p+1,p+1+n,sort_by_x); dp[1]=0; CDQ(1,n); PF("%lld",dp[n]); } /* 6 3 8 7 1 6 6 0 -1 9 1 2 0 */