传送门
g
[
i
]
[
j
]
[
k
]
[
l
]
g[i][j][k][l]
g[i][j][k][l]表示将区间
l
,
r
l,r
l,r变成最小值等于
k
k
k,最大值等于
l
l
l时的花费的最优值。
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示取掉区间
l
,
r
l,r
l,r的最优值。
考虑
g
g
g数组的转移。
g
[
i
]
[
j
+
1
]
[
m
i
n
(
k
,
w
[
j
+
1
]
)
]
[
m
a
x
(
l
,
w
[
i
+
1
]
)
]
=
m
i
n
(
g
[
i
]
[
j
+
1
]
[
m
i
n
(
k
,
w
[
j
+
1
]
)
]
[
m
a
x
(
l
,
w
[
i
+
1
]
)
]
,
g
[
i
]
[
j
]
[
k
]
[
l
]
)
g[i][j+1][min(k,w[j+1])][max(l,w[i+1])]=min(g[i][j+1][min(k,w[j+1])][max(l,w[i+1])],g[i][j][k][l])
g[i][j+1][min(k,w[j+1])][max(l,w[i+1])]=min(g[i][j+1][min(k,w[j+1])][max(l,w[i+1])],g[i][j][k][l])
g
[
i
]
[
t
]
[
k
]
[
l
]
=
m
i
n
(
g
[
i
]
[
t
]
[
k
]
[
l
]
,
g
[
i
]
[
j
]
]
[
k
]
[
l
]
+
f
[
i
+
1
]
[
t
]
)
g[i][t][k][l]=min(g[i][t][k][l],g[i][j]][k][l]+f[i+1][t])
g[i][t][k][l]=min(g[i][t][k][l],g[i][j]][k][l]+f[i+1][t])
然后再用
g
g
g数组更新
f
f
f数组。
f
[
l
]
[
r
]
=
m
i
n
(
f
[
l
]
[
r
]
,
g
[
l
]
[
r
]
[
k
]
[
l
]
)
f[l][r]=min(f[l][r],g[l][r][k][l])
f[l][r]=min(f[l][r],g[l][r][k][l])
这样维护就行了。
注意
d
p
dp
dp之前离散化一下。
代码:
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
const int N=55;
int n,a,b,f[N][N],g[N][N][N],w[N],x[N],tot=0;
int main(){
n=read(),a=read(),b=read();
for(int i=1;i<=n;++i)w[i]=x[i]=read();
sort(x+1,x+n+1),tot=unique(x+1,x+n+1)-x-1;
for(int i=1;i<=n;++i)w[i]=lower_bound(x+1,x+tot+1,w[i])-x;
for(int i=1;i<=n;++i)f[i][i]=a;
for(int len=2;len<=n;++len)for(int l=1,r=len;r<=n;++l,++r){
for(int i=l;i<=r;++i)for(int j=tot;j;--j)for(int k=tot;k>=j;--k)g[i][j][k]=0x3f3f3f3f;
g[l][w[l]][w[l]]=0;
for(int i=l;i<r;++i)for(int j=tot;j;--j)for(int k=tot;k>=j;--k){
if(g[i][j][k]==0x3f3f3f3f)continue;
int&tmp=g[i+1][min(j,w[i+1])][max(k,w[i+1])];
tmp=min(tmp,g[i][j][k]);
for(int t=i+1;t<=r;++t)g[t][j][k]=min(g[t][j][k],g[i][j][k]+f[i+1][t]);
}
f[l][r]=0x3f3f3f3f;
for(int i=tot;i;--i)for(int j=tot;j>=i;--j)f[l][r]=min(f[l][r],g[r][i][j]+a+b*(x[i]-x[j])*(x[i]-x[j]));
}
cout<<f[1][n];
return 0;
}