能量项链 P1063(Luogu)
题目Luogu或者题目AcWing
一道区间\(DP\),设计状态\(f[i][j]\)表示合并\(i\to j\)的最大价值,那么合并\(i,j\)的最大价值应该是从某个最后一步转移过来,也就是某一步合并\(i,j\)的转移过来,所以枚举这个\(k\),就可以转移了。
需要注意的几个细节就是
- 环形要加倍,就可以变成链问题,为什么可行?考虑一个环,\(n\)个点间有\(n\)个空隙,每次通过一个空隙合并,都会少一堆,于是如果\(n\)个空隙都合并了,应该是\(0\)堆,所以不可能,所以有一个空隙一定没有使用,即 最优方案一定可以把环从某处拆开,拆开的这里不会有贡献,于是可以拆成\(n\)个开头的链。
- 注意初始化的时候,一个项链是没有能量的,\(f[i][i]=0\),还有就是注意给出的是头部,最后一个的尾部应该是第一个的头部,这个特殊设置一下就行。
- 因为环形加倍了,所以数组要两倍,否则\(\mathcal{RE}\)警告
\(\mathcal{CODE:}\)
#include <bits/stdc++.h>
using namespace std;
const int N = 208;
int n;
int a[N];
int f[N][N];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),a[n+i]=a[i];
a[2*n+1]=a[1];
for(int len=2;len<=n;len++){
for(int l=1;l+len-1<=2*n;l++){
int r=l+len-1;
for(int k=l;k<r;k++){
f[l][r]=max(f[l][r],f[l][k]+f[k+1][r]+a[l]*a[k+1]*a[r+1]);
}
}
}
int res=0;
for(int i=1;i<=n;i++)res=max(res,f[i][i+n-1]);
printf("%d\n",res);
return 0;
}
我不想就这样沦陷,迷失在黑夜,我将燃烧这生命,就算再壮烈。