显然 $dp$,首先设 $f[i][j]$ 表示当前考虑到第 $i$ 个电线杆,高度为 $j$ 时的最小代价
那么有转移 $f[i][j]=f[i-1][k]+cost+C(j-k)$,其中 $j>=k$,$cost$ 为把电线杆 $i$ 增高到 $j$ 的代价,$i,j$ 固定时为常数
对于 $i,j$ 的最优转移 $k'$,$i,j+1$ 时小于 $j$ 的所有转移代价同时增加 $C$,所有对于 $k<j$ 的位置只有 $k'$ 有机会贡献
当 $k>j$ 时也同理,动态维护即可
其实直接维护前缀 $f[i][j]-Ck$ 最小值会好写很多...
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=1e5+7,M=107; const ll INF=1e18; int n,C,h[N],H; ll f[2][M],ans=INF; inline ll calc(int i,int j,int k) { return f[(i&1)^1][k]+(j-h[i])*(j-h[i])+C*abs(j-k); } int main() { n=read(),C=read(); for(int i=1;i<=n;i++) h[i]=read(),H=max(H,h[i]); for(int i=h[1];i<=H;i++) f[1][i]=(i-h[1])*(i-h[1]); for(int i=2;i<=n;i++) { int pre=h[i-1],p=i&1; for(int j=0;j<=H;j++) f[p][j]=INF; for(int k=pre+1;k<h[i];k++) if(calc(i,h[i],pre)>calc(i,h[i],k)) pre=k; for(int j=max(h[i],h[i-1]);j<=H;j++) { if(calc(i,j,pre)>calc(i,j,j)) pre=j; f[p][j]=calc(i,j,pre); } pre=H; for(int j=H-1;j>=h[i];j--) { if(j+1>=h[i-1] && calc(i,j,pre)>calc(i,j,j+1)) pre=j+1; f[p][j]=min(f[p][j],calc(i,j,pre)); } } for(int i=h[n];i<=H;i++) ans=min(ans,f[n&1][i]); printf("%lld ",ans); return 0; }