#dp#JZOJ 1281 旅行
分析
考虑每次都是取出一个连续段置换一下,
可以预处理出相邻差的绝对值的前缀和,
但是如果正序无法知道上一段是从哪个终止的
所以倒序就可以了
代码
#include <cstdio>
#include <cctype>
#include <bitset>
#define rr register
using namespace std;
const int N=2011; typedef long long lll;
int a[N],n; lll dp[N][2],s[N];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline lll min(lll a,lll b){return a<b?a:b;}
inline signed Abs(int x){return x<0?-x:x;}
signed main(){
n=iut(); for (rr int i=1;i<=n;++i) a[i]=iut();
for (rr int i=2;i<=n;++i) s[i]=s[i-1]+Abs(a[i]-a[i-1]);
dp[n-1][0]=dp[n-1][1]=Abs(a[n]-a[n-1]);
for (rr int i=n-2;i;--i){
dp[i][0]=min(dp[i+1][0]+Abs(a[i+1]-a[i]),dp[i+1][1]+Abs(a[i+2]-a[i]));
dp[i][1]=min(s[n-1]-s[i+1]+Abs(a[n-1]-a[i])+Abs(a[n]-a[i]),s[n]-s[i+1]+Abs(a[n]-a[i]));
for (rr int j=i+1;j<n-1;++j)
dp[i][1]=min(dp[i][1],min(dp[j+1][0]+Abs(a[j+1]-a[i]),dp[j+1][1]+Abs(a[j+2]-a[i]))+s[j]-s[i+1]+Abs(a[j]-a[i]));
}
return !printf("%lld",min(dp[1][0],dp[1][1]));
}