这题感觉真是太神了....

看了网上很多题解,最后参考了这个: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\n",dp[1][n]);
52     return 0;
53 }

 

posted on 2017-05-26 20:02  Vergil_LY  阅读(292)  评论(0编辑  收藏  举报