1705. [Usaco2007 Nov]Telephone Wire 架设电话线

传送门

显然 $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\n",ans);
    return 0;
}

 

posted @ 2019-08-26 10:05  LLTYYC  阅读(160)  评论(0编辑  收藏  举报