题目大意
- n颗珠子串成一圈,可以头尾合并;
- 只能相邻的合并,合并后原地变成一颗新的珠子,头尾不变;
- 求用什么顺序合并,得到的能量最大。
题目分析
- 这题和石子合并,堪称区间DP的模板级:
1 处理成环的问题;
2 搞清楚每颗珠子的前后关系;
思路:
- 问什么设什么:f[i][j]表示从i合并到j得到的最大能量;
- 开双倍的空间,解决“环”的问题;
- 三层循环:
1 第一层循环:从小到大枚举长度(2个相邻的合并,然后是3个/4个。。。依次类推);
2 第二层循环:枚举当前长度的开头s,那么当前的结束e,就是s+l-1;
3 第三层循环:枚举当前这个长度的中间点 i,从s~ i 属于左边部分, i+1 ~ e 属于右边部分; - 枚举长度为 n 的情况,找最大值:
参考代码
//luogu1063:能量项链
//区间DP
//环状石子合并一样的思路
#include<bits/stdc++.h>
using namespace std;
int n,a[210],ans=0;
int f[210][210];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[i+n]=a[i];//成环,所以存2倍的长度
}
a[2*n+1]=a[1];//最后一格的尾巴,是第一格
//区间DP
memset(f,0,sizeof(f));
for(int l=2;l<=n;l++)//组合的长度
{
for(int s=1;s<=2*n-l;s++)//组合的开头
{
int e=s+l-1;//组合的结尾
for(int i=s;i<e;i++)//断点 (包头不包尾巴)
{
f[s][e]=max(f[s][e],f[s][i]+f[i+1][e]+a[s]*a[i+1]*a[e+1]);
}
}
}
//枚举对应长度值,更新答案
for(int i=1;i<=n;i++)
{
ans=max(ans,f[i][i+n-1]);
}
printf("%d",ans);
return 0;
}