参考博客 http://blog.youkuaiyun.com/zizaimengzhongyue/article/details/9413387 dfs http://blog.youkuaiyun.com/keyboarderqq/article/details/51878796 *** http://www.bubuko.com/infodetail-788716.html
分析:
题目要求从两边取,权值为a[i]*cnt,这样就很不好处理。
假设从里面往外取,取最里面的那个权值为a[i]n,倒数第二个为a[j](n-1),
dp[i][j]表示取完[i,j]区间的最大值,那么由dp[i][i]很容易得到dp[i][i+1];
dp[i][j]=max(dp[i+1][j]+a[i]*cnt,dp[i][j-1]+a[j]*cnt); (cnt为第几次取数字)
最终答案就是dp[1][n];
题意:给出的一系列的数字,可以看成一个双向队列,每次只能从队首或者队尾出队,第n个出队就拿这个数乘以n,最后将和加起来,求最大和
code
:
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<queue>
using namespace std;
#define ll long long
#define mem(a,t) memset(a,t,sizeof(a))
#define N 2005
const int M=100005;
const int inf=0x1f1f1f1f;
int a[N],dp[N][N];
int main()
{
int i,j,k,n;
while(~scanf("%d",&n))
{
mem(dp,0);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]); //从里向外逆推区间
dp[i][i]=a[i]*n; //最后取的是a[i]
}
for(k=1;k<n;k++) //区间长度为k+1时
{
for(i=1;i+k<=n;i++) //枚举区间长度为k+1的每个区间起点
{
j=i+k; //该区间终点为j=i+k
dp[i][j]=max(dp[i+1][j]+a[i]*(n-k),dp[i][j-1]+a[j]*(n-k));
} //该区间的最优解为先取左边或者右边两者的最大值
}
printf("%d\n",dp[1][n]);
}
return 0;
}