能量项链 环状DP模板题目

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=210;
//环状DP
ll dp[N][N];
int a[N],n;//开二倍数组
int main()
{
		cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];	//初始化
		a[n+i]=a[i];//倍增数组 i和1要分清
	}
	for(int len=2;len<=n;len++)	
  //区间长度len
	//左端点l
	//右端点r
	{
		for(int l=1;l+len-1<2*n;l++)//约束区间起始点
		{
			int r =l+len-1;
			for(int k=l;k<r;k++)//设置断点
			{//同所有的情况进行比较
			//原来的能量+新产生的能量
				dp[l][r]=max(dp[l][r],dp[l][k]+dp[k+1][r]+a[l]*a[k+1]*a[r+1]);
			}
		}
	}
	//对每一个点全部截断取最值
	ll ans=0;
	for(int i=1;i<=n;i++) ans=max(ans,dp[i][i+n-1]);
	cout<<ans<<endl;
	return 0;
}
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
const int N=110;
int n,a[N<<1];
ll dp[N<<1][N<<1];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++) a[i+n]=a[i];
	for(int l=2;l<=n;l++)//区间长度小于3的时候不执行没有意义 
		for(int i=1;(i+l-1)<=(2*n-1);i++)
		{//保证右端点的范围
    //i+l-1表示区间的右端点
    //2n是复制之后最后一个珠子的索引
    //2n-1是因为不用遍历到复制之后的最后一个珠子
    //n-2n和1-n没有区别
			int j=i+l-1;//定义右端点
			for(int k=i;k<j;k++)//断点从左端点开始小于右端点
				dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+1ll*a[i]*a[k+1]*a[j+1]);
    //dp[i][k]表示合并区间[i,j]能够获得的最大分数
		//a[i]是第i-1颗珠子的为
		}    
		//2  3  5  10
		/*若 
		i指向2 
		k指向3 
		j指向10
		那么1ll*a[i]*a[k+1]*a[j+1]就是2*5*2
		此时表示将A(2 3)和B(5 10)进行合并,A合并之后的头为2 尾标记为5 B合并之后头标记为5 尾标记为2(10是最后一颗珠子,首尾相连) 
		*/
	ll ans=0;
	for(int i=1;i<=n;i++) ans=max(ans,dp[i][i+n-1]);
	printf("%lld\n",ans);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值