区间dp题, 题目已经明示项链, 说明成环状的, 录入数组元素的时候让其下标+n=该下标下的元素即可(记得数组开两倍):
for(int i=1;i<=n;i++)
{
cin>>arr[i];
arr[i+n]=arr[i];
}
接下来就是关于区间dp的状态转移方程, 所谓区间dp, 无非就是两个区间合并产生额外的值, 让你求最终最大的值或最小的值.
这题是非常典型的区间dp, 对于这题来说, 我们需要枚举左区间和右区间再加上两个区间合并的值, 即状态转移方程:
f[j][i]=max(f[j][i],f[j][k]+f[k+1][i]+arr[i+1]*arr[k+1]*arr[j]);
从j到i的这一段区间可以有(i-j-1)个合成方式, 这时候就需要k来枚举每一次的合成, 取最大值
ac代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <string>
#include <stack>
#include <deque>
#include <map>
#include <set>
using namespace std;
#define ll long long
#define endl "\n"
#define rep(i, a, b) for (ll i = (a); i <= (b); i++)
#define repr(i, a, b) for (ll i = (a); i < (b); i++)
#define rrep(i, a, b) for (ll i = (b); i >= (a); i--)
#define rrepr(i, a, b) for (ll i = (b); i > (a); i--)
#define min(a,b) (a)<(b)?(a):(b)
#define max(a,b) (a)>(b)?(a):(b)
ll cnt,n,m,t,ans,ant;
const int N=5e2+10;
ll arr[N],f[N][N];
string str;
inline ll read()
{
char c = getchar();int x = 0,s = 1;
while(c < '0' || c > '9') {if(c == '-') s = -1;c = getchar();}//是符号
while(c >= '0' && c <= '9') {x = x*10 + c -'0';c = getchar();}//是数字
return x*s;
}
void solve()
{
n=read();
rep(i,1,n)
{
arr[i]=read();
arr[i+n]=arr[i];//链式
}
//左珠头m*左珠尾r*右珠尾n
//合并后产生mnr能量
//新珠子mn开头
repr(i,2,2*n)//枚举右珠子
for(ll j=i-1;j>0&&j>i-n;j--)//枚举左珠子
{
repr(k,j,i)//k为j到i的两珠分界线(枚举i到j合并的不同方式), i到j珠子最终会合并为一个珠子
f[j][i]=max(f[j][i],f[j][k]+f[k+1][i]+arr[i+1]*arr[k+1]*arr[j]);
//左边+右边+合并
}
ans=-1;
rep(i,1,n)
ans=max(ans,f[i][n+i-1]);//一整条项链
cout<<ans;
return;
}
int main()
{
solve();
return 0;
}