P1063 [NOIP2006 提高组] 能量项链

原题链接

考察:区间dp

思路:

        根据题目我们可以发现,当相邻两颗珠子合并时,只剩下首尾,中间部分不关心.

        我们回顾一下区间dp,f[l][r]表示将[l,r]区间内的石子合并(以模板题为例),中间是什么我们也不关心,而f数组求最值是以某个分割点k来划分集合.

        f[l][r] = max(f[l][k]+f[k][r],f[l][r])         这里的分割点k,也是将[l,r]划分为[l,k][k,r]两个区间.

        那么这道题也可以用区间dp做.根据题目发现我们需要将4与1连在一起,但是将4,1连在一起还是不够,我们发现(4,1)的新珠子还可以和2融合.所以这里我们需要断环成链,构造2倍长度的a数组.最后答案是以某点i为起点,区间长度为n取max

        本题的转移方程f[l][r] = max(f[l][k]+f[k][r]+a[l]*a[k]*a[r],f[l][r]) 融合是三个不同点融合,因此k不能与l,r相同. a[l]*a[k]*a[r]就是将[l,k][k,r]看成一个珠子.

 1 #include <iostream>
 2 #include <cstring>
 3 using namespace std;
 4 const int N = 210;
 5 int a[N],f[N][N],n;
 6 int main()
 7 {
 8     scanf("%d",&n);
 9     for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i+n] = a[i];
10     for(int len=3;len<=2*n;len++)
11       for(int l=1;l+len-1<=2*n;l++)
12       {
13           int r = l+len-1;
14           for(int k=l+1;k<r;k++)
15             f[l][r] = max(f[l][k]+f[k][r]+a[l]*a[k]*a[r],f[l][r]);
16       }
17     int ans = 0;
18     for(int i=1;i<=n;i++) ans = max(ans,f[i][i+n]);
19     printf("%d\n",ans);
20     return 0;
21 }

 

总结:

        区间dp只考虑首尾,常常以枚举断点来划分集合.

posted @ 2021-04-03 16:11  acmloser  阅读(122)  评论(0编辑  收藏  举报