洛谷P1063 能量项链

P1063 能量项链

洛谷P1063 能量项链_第1张图片

 

洛谷P1063 能量项链_第2张图片

 

 这个题是一个十分经典的区间dp,也是最基础的区间dp

大体思路就是将大区间化为小区间去做,再通过小区间dp回来求大区间

首先,我们发现尽管题目中有着许多的关于吸盘的描述,实际上都是在搞心态

精简一下题目,就是给你一个环形的序列,让你求a[l]*a[k]*a[r]在每个区间合并时的取值的最大价值,与合并石子有类似的地方,但是本题的价值取数和之前合并石子的价值取数有所不同,在取值时是三个数的乘积相加(也就是题目中所说的那个通过吸盘来吸取其中的能量,即能量珠子的头标记,尾标记和自身的乘积,也就是我们的价值取数)

我们在设置dp数组时也去选择最简洁的dp[l][r]来表示在序列区间[l,r]上的最大价值,显然,我们只需要去枚举断点来进行dp就可以了

dp方程也不难理解:dp[l][r]=max(dp[l][r],dp[l][k]+dp[k][r]+a[l]*a[k]*a[r])

这里需要注意的点就是这个,枚举的时候应该先去枚举那个dp区间的长度i

只有先去确定好我们所要枚举的区间长度才能去进行之后的操作

这里还需要注意的地方就是那个环了,我们既可以通过%操作去实现环形也可以通过2*n数组去进行模拟这个环

我选择了后者,因为代码难度相对较小

代码如下:

#include
using namespace std;
inline int read()
{
    int a=0,b=1;
    char c=getchar();
    while(!isdigit(c))
    {
        if(c=='-')
            b=-1;
        c=getchar();
    }
    while(isdigit(c))
    {
        a=(a<<1)+(a<<3)+(c^48);
        c=getchar();
    }
    return a*b;
}
int a[205],dp[205][205];
int main()
{
    int n=read();
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
        a[i+n]=a[i];
    }
    for(int i=2;i<=n+1;i++)
        for(int l=1;l+i-1<=2*n;l++)
        {
            int r=l+i-1;
            for(int k=l+1;k<=l+i-2;k++)
                dp[l][r]=max(dp[l][r],dp[l][k]+dp[k][r]+a[l]*a[k]*a[r]);
        }
    int ans=0;
    for(int i=1;i<=n;i++)
        ans=max(ans,dp[i][i+n]);
    printf("%d",ans);
    return 0;
}

 

你可能感兴趣的:(洛谷P1063 能量项链)