这题感觉真是太神了....
看了网上很多题解,最后参考了这个:http://blog.csdn.net/hld67890/article/details/72556554
首先我们容易想到区间DP,令DP[i][j]表示将[i,j]这段区间全部取完的最小代价,那么我们要如何转移呢?我们发现DP[i][j]的转移过程其实是在[i,j]中选一个子序列,然后我们将这个区间取成只剩这个子序列,然后再将这个子序列取走。这样我们就需要DP套DP,令fz[o][p1][p2]表示在[i,j]中考虑到了o这个数,最大值的位置在p1,最小值的位置在p2的方案数,那么这个DP的转移就是考虑一下o+1这个数,以及枚举子序列的间隔,间隔的代价我们已经得到了(因为[i,j]的子区间的DP值我们都已经算出了),这样fz数组也可以求出来了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define maxn 55 6 const int INF=1000000000; 7 int dp[maxn][maxn],fz[maxn][maxn][maxn]; 8 int n,a,b,w[maxn]; 9 10 void getdp(int l,int r) 11 { 12 for (int i=l;i<=r;i++) 13 for (int j=l;j<=i;j++) 14 for (int k=l;k<=i;k++) 15 fz[i][j][k]=INF; 16 fz[l][l][l]=0; 17 for (int i=l;i<=r;i++) 18 { 19 fz[i][i][i]=min(fz[i][i][i],dp[l][i-1]); 20 for (int j=l;j<=i;j++) 21 for (int k=l;k<=i;k++) 22 { 23 if (fz[i][j][k]==INF) continue; 24 int t1= w[j]>w[i+1]?j:i+1; 25 int t2= w[k]<w[i+1]?k:i+1; 26 fz[i+1][t1][t2]=min(fz[i][j][k],fz[i+1][t1][t2]); 27 for (int o=i+1;o<=r;o++) 28 fz[o][j][k]=min(fz[o][j][k],fz[i][j][k]+dp[i+1][o]); 29 } 30 } 31 } 32 33 int main() 34 { 35 scanf("%d",&n); 36 scanf("%d%d",&a,&b); 37 for (int i=1;i<=n;i++) scanf("%d",&w[i]); 38 for (int len=1;len<=n;len++) 39 for (int l=1;l+len-1<=n;l++) 40 { 41 int r=l+len-1; 42 dp[l][r]=INF; 43 getdp(l,r); 44 for (int i=l;i<=r;i++) 45 for (int j=l;j<=r;j++) 46 { 47 if (fz[r][i][j]==INF) continue; 48 dp[l][r]=min(dp[l][r],fz[r][i][j]+a+b*(w[i]-w[j])*(w[i]-w[j])); 49 } 50 } 51 printf("%d ",dp[1][n]); 52 return 0; 53 }