思路是 fl,r,l1 表示把区间 [l,r] 变成 [l1,l1+r−l] 最小的代价,从两个方向转移:一个是对应位置直接加代价,一个是枚举断点交换对应区间。
#include<cstdio>
using namespace std;
__int128 f[23][23][23];
__int128 a[23],b[23];
inline __int128 abs(__int128 x){
return x<0?-x:x;
}
inline __int128 min(__int128 H,__int128 G){
return H<G?H:G;
}
template<typename _T>
inline void read(_T &x){
char c;
c=getchar();
while(c<'0'||c>'9'){
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<3)+(x<<1)+(c&15);
c=getchar();
}
}
inline void write(__int128 x){
if(x<(__int128)(10)){
putchar(x|'0');
return;
}
write(x/10);
putchar((x%10)|'0');
}
int n;
__int128 c;
int main(){
read(n);read(c);
for(int i=1;i<=n;++i){
read(a[i]);
}
for(int i=1;i<=n;++i){
read(b[i]);
}
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
f[i][i][j]=abs(a[i]-b[j]);
}
}
for(int len=2;len<=n;++len){
for(int l=1,r=len;r<=n;++l,++r){
for(int l1=1;l1+len-1<=n;++l1){
for(int k=0;k<len;++k){
f[l][r][l1]+=abs(a[l+k]-b[l1+k]);
}
for(int k=0;k<len-1;++k){
f[l][r][l1]=min(f[l][r][l1],f[l][l+k][l1+len-1-k]+f[l+k+1][r][l1]+c);
}
}
}
}
write(f[1][n][1]);
return 0;
}