能量项链
https://loj.ac/problem/10148
题目描述
有\(n\)个珠子排成一圈,每个珠子有头标记和尾标记,对于\(i<n\),第\(i\)个珠子的尾标记等于第\(i+1\)个珠子的头标记,第\(n\)个珠子的尾标记等于第\(1\)个珠子的头标记,每次合并时,记前一个珠子的头标记为\(m\),尾标记为\(r\),后一个珠子的尾标记为\(n\),那么会产生\(m*r*n\)的能量和一颗头标记为\(m\),尾标记为\(n\)的珠子,求合并产生的最大能量和。
思路
依然是把环化为链做,类似的,我们用\(f[i][j]\)表示合并\(i\)到\(j\)段的珠子的能量和,那么转移方程即为\(f[i][j]=max\{f[i][k]+f[k+1][j]+s[i]*s[k]*s[j]\}\),以区间长度作为第一维即可。
代码
#include <bits/stdc++.h>
using namespace std;
int read()
{
int res=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
return res*w;
}
int head[220],tail[220],f[220][220];
int main()
{
int n=read();
for(int i=1;i<=n;i++)
head[i]=read(),head[i+n]=head[i];
for(int i=1;i<n*2;i++)
tail[i]=head[i+1];
tail[n*2]=head[1];
for(int len=2;len<=n;len++)
for(int l=1;l<=n*2-len+1;l++)
{
int r=l+len-1;
f[l][r]=0;
for(int k=l;k<r;k++)
f[l][r]=max(f[l][r],f[l][k]+f[k+1][r]+head[l]*tail[k]*tail[r]);
}
int ans=0;
for(int i=1;i<=n;i++)
ans=max(ans,f[i][i+n-1]);
printf("%d",ans);
return 0;
}