传送门
解析:
莫名其妙写了一个O(n4)O(n^4)O(n4)的区间DP,结果一发过不了大样例。。。
然而标算的复杂度是O(n5)O(n^5)O(n5)???才发现自己的DP考虑的太片面了(就是错了)。
思路:
首先讲一个错误思路,一个区间中间抽走一个,两边的合并起来,这样子DP就是O(n4)O(n^4)O(n4)。
为什么是错的,很显然是错的啊。。。
万一这个区间的最优解是多抽走几个单独的区间,剩下的区间一起合并,那么这个做法就显然gggggg了。
所以我们考虑另一种DP:
设gl,r,mn,mxg_{l,r,mn,mx}gl,r,mn,mx表示使得原区间<l,r><l,r><l,r>中剩下的数最大值为mxmxmx,最小值为mnmnmn所需要的最小代价,fl,rf_{l,r}fl,r表示将区间<l,r><l,r><l,r>中的所有数全部抽走需要的最小代价。
显然ggg数组的处理需要fff数组,fff数组的更新也需要ggg数组(真是蛋疼)。
考虑区间DP,设当前处理的是区间长度为LLL,即所有长度小于LLL的区间的fff都已经处理出来了
当前处理的是区间<l,r><l,r><l,r>,那么我们需要处理出gl,r,mn,mxg_{l,r,mn,mx}gl,r,mn,mx对所有可能的mn,mxmn,mxmn,mx的答案,ggg的处理也考虑DP,并且需要用到已经处理了的fff数组。
显然gl,l,wl,wl=0g_{l,l,w_l,w_l}=0gl,l,wl,wl=0,转移的边界就是这个。
那么显然对于每个状态gl,i,mn,mxg_{l,i,mn,mx}gl,i,mn,mx,考虑保留r+1r+1r+1位置的数,则有转移checkmin(gl,i+1,min(mn,wi+1),max(mx,wi+1),gl,i,mn,mx)checkmin(g_{l,i+1,min(mn,w_{i+1}),max(mx,w_{i+1})},g_{l,i,mn,mx})checkmin(gl,i+1,min(mn,wi+1),max(mx,wi+1),gl,i,mn,mx),其中checkmincheckmincheckmin函数的作用就是比较两个参数,并且将第一个参数变成两个中的较小值。
然后考虑贪心转移一下所有i<t≤ri < t \leq ri<t≤r的gl,t,mn,mxg_{l,t,mn,mx}gl,t,mn,mx,这个直接贪心转移,考虑将<i+1,t><i+1,t><i+1,t>区间中的所有数直接抽出来,剩下的必然满足原来的限制,转移就是checkmin(gl,t,mn,mx,gl,i,mn,mx+fi+1,t)checkmin(g_{l,t,mn,mx},g_{l,i,mn,mx}+f_{i+1,t})checkmin(gl,t,mn,mx,gl,i,mn,mx+fi+1,t)
然后我们就处理好了所有当前需要的ggg,fff的转移也十分明显了,将数组抽到最小值为mnmnmn,最大值为mxmxmx,然后直接一次将剩余的部分全部抽完的代价就是gl,r,mn,mx+a+b∗(mx−mn)2g_{l,r,mn,mx}+a+b*(mx-mn)^2gl,r,mn,mx+a+b∗(mx−mn)2。
实际上我们并不需要维护四维的ggg,只需要维护三维,因为在一段状态中的lll总是不变的,每次DP前初始化一下就行了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
inline void ckmin(int &a,cs int &b){
a<=b?0:(a=b);
}
cs int N=55,INF=0x3f3f3f3f;
int g[N][N][N],f[N][N],a,b;
int w[N],v[N],len;
int n;
signed main(){
n=getint();
a=getint();
b=getint();
for(int re i=1;i<=n;++i)v[i]=w[i]=getint();
sort(w+1,w+n+1);
len=unique(w+1,w+n+1)-w-1;
for(int re i=1;i<=n;++i)v[i]=lower_bound(w+1,w+len+1,v[i])-w;
memset(f,0x3f,sizeof f);
for(int re i=1;i<=n;++i)f[i][i]=a;
for(int re L=2;L<=n;++L){
for(int re l=1,r=L;r<=n;++l,++r){
for(int re i=l;i<=r;++i)
for(int re mn=1;mn<=len;++mn)
for(int re mx=mn;mx<=len;++mx)
g[i][mn][mx]=INF;
g[l][v[l]][v[l]]=0;
for(int re i=l;i<r;++i){
for(int re mn=len;mn;--mn)
for(int re mx=len;mx>=mn;--mx){
if(g[i][mn][mx]==INF)continue;
ckmin(g[i+1][min(mn,v[i+1])][max(mx,v[i+1])],g[i][mn][mx]);
for(int re j=r;j>i;--j)ckmin(g[j][mn][mx],g[i][mn][mx]+f[i+1][j]);
}
}
for(int re mn=len;mn;--mn)
for(int re mx=len;mx>=mn;--mx)
ckmin(f[l][r],g[r][mn][mx]+a+b*(w[mx]-w[mn])*(w[mx]-w[mn]));
}
}
cout<<f[1][n];
return 0;
}