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;
}