我的思维漏洞
我找了好久的题解啊,最后只好对着别人提交的代码改错。。 我起初自认为找到了最优解的数学表达,即:
当我选择其中一点为起点后,只要我比较左右位置的a[i]大小,每次总优先跳到小的格子上,让大的格子尽量延后。这样我就可以得到当前起点下的最优解
如此,我只要枚举起点就好了。。
事实证明我错了,我花了好长时间来找反例。虽然标签说明了是区间DP,但我就是想尝试一下(呜呜~)
下面是正确的代码。
以二维数组下标作为左右区间端点,区间长度从1到n依次填表。大家都明白,不说了·
#include<iostream>
using namespace std;
int a[4100];
int dp[4100][4100];
//环形,无脑开两倍数组(其实也可以不开,就是处理时麻烦一点点)
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; ++i)
{
cin >> a[i];
dp[i][i]=a[i];
}
for(int i=n+1;i<=n+n;++i)
{
a[i]=a[i-n];
}
for(int len=1;len<=n;++len)//枚举区间长度
{
//枚举左端点
//for(int i=1;i<=2*n-len+1;++i) //法1:直接将n~2n的表也填上,这样就不用考虑那么多啦
for(int i=1;i<=n;++i) //法2:将循环改为拷贝,本质还是和法1一样,填表
{
int j=i+len-1;
dp[i][j]=max(dp[i+1][j]+len*a[i],dp[i][j-1]+len*a[j]);
if(i>=1&&j<=n)
dp[i+n][j+n]=dp[i][j];
}
}
//找最大区间
int maxn=0;
for(int i=1;i<=n;++i)
{
maxn=max(maxn,dp[i][i+n-1]);
}
cout<<maxn;
}