#dp#JZOJ 1281 旅行

BDBqxS.png


分析

考虑每次都是取出一个连续段置换一下,
可以预处理出相邻差的绝对值的前缀和,
但是如果正序无法知道上一段是从哪个终止的
所以倒序就可以了


代码

#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]));
} 
posted @ 2020-11-02 16:42  lemondinosaur  阅读(65)  评论(0编辑  收藏  举报