1326: 生命仪式
时间限制: 5 Sec 内存限制: 128 MB提交: 12 解决: 7
题目描述
tsy的另一个身份是一位mo法师,他准备进行一个生命延续的仪式(为一位长者),仪式的规则是这样的,N个人围成一圈(N号与1号相邻,其余依次相邻),每个人有一个能量值ai,每次选取圈内的一个人进行献祭,这个人立刻退(ren)出(jian)仪(zheng)式(fa),而长者则得到一些时间,时间的大小为选取人选和当前左右两人的能量之积(左右两人在还剩两人时是重复的),最后还剩一人时仪式结束,现在问你怎样操作这个仪式可以使得长者得到的时间总量最大。
输入
多组数据
每组第一行一个数字N代表人数(2 <= N <= 400)
之后N个数字ai代表第i人的能量值(ai <= 150)
输出
一行一个数字,代表得到的最大时间
样例输入
2
4 2
样例输出
32
提示
这不是贪心
来源
环形区间DP的模版题
一个操作代表权值,最后有一个终止条件。
思考什么时候终止便可以得到状态
很显然只剩下一个的时候游戏终止 则状态可以表示为区间i j 取到只剩下i的时候的最大值
状态转移方程
dp[i][j]=max(,dp[i][k]+dp[k+1][j]+a[i]*a[k+1]*a[j+1])
或者也可以将状态标示为剩下I j 其实大体思路是一样的。
#include<bits/stdc++.h>
using namespace std;
const int maxn=410;
long long a[maxn];
//相当于合并石子的逆过程
//
long long dp[maxn][maxn];
typedef long long ll;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
//
//dp [i][j] max(dp[i][j],dp[k+1][k-1]+a[k+1]*a[k]*a[k-1]);
int N;
int main(){
while(~scanf("%d",&N))
{
for(int i=0;i<N;i++)
{
a[i]=read();
}
memset(dp,0,sizeof(dp));
for(int i=1;i<=N;i++)//枚举长度
{
for(int j=0;j<N;j++)//枚举左端点
{
int end=j+i%N;
for(int k=j;k<j+i;k++)//中间点
{
dp[j][end]=max(dp[j][end],dp[j][k%N]+dp[(k+1)%N][end]+a[j]*a[(k+1)%N]*a[(end+1)%N]);
//cout<<i<<" "<<endl;
}
}
}
long long res=0;
for(int i=0;i<N;i++)
{
res=max(res,dp[i][(i+N-1)%N]);
}
printf("%lld\n",res);
}
return 0;
}