题意
约翰经常给产奶量高的奶牛发特殊津贴,于是很快奶牛们拥有了大笔不知该怎么花的钱。为此,约翰购置了 N ( 1 ≤ N ≤ 2000 ) N(1≤N≤2000) N(1≤N≤2000) 份美味的零食来卖给奶牛们。每天约翰售出一份零食。当然约翰希望这些零食全部售出后能得到最大的收益,这些零食有以下这些有趣的特性:
零食按照
1
,
…
,
N
1,…,N
1,…,N 编号,它们被排成一列放在一个很长的盒子里。盒子的两端都有开口,约翰每天可以从盒子的任一端取出最外面的一个。
与美酒与好吃的奶酪相似,这些零食储存得越久就越好吃。当然,这样约翰就可以把它们卖出更高的价钱。
每份零食的初始价值不一定相同。约翰进货时,第i份零食的初始价值为
V
i
(
1
≤
V
≤
1000
)
V_i(1≤V≤1000)
Vi(1≤V≤1000)。
第i份零食如果在被买进后的第
a
a
a 天出售,则它的售价是
V
i
×
a
V_i ×a
Vi×a。
V
i
V_i
Vi
表示的是从盒子顶端往下的第i份零食的初始价值。约翰告诉了你所有零食的初始价值,并希望你能帮他计算一下,在这些零食全被卖出后,他最多能得到多少钱。
思路
考虑动态规划,记 d p i , j dp_{i,j} dpi,j 表示前 i i i次操作中 j j j 次从顶端拿走 j j j 次最多赚到的钱,则因为每次可以从顶部和底部拿:
d p i , j = max ( d p i − 1 , j + a n − ( i − j ) + 1 × i , d p i − 1 , j − 1 + a i × i ) dp_{i,j} = \max(dp_{i - 1,j} + a_{n-(i -j)+1} \times i,dp_{i-1,j-1} + a_i \times i) dpi,j=max(dpi−1,j+an−(i−j)+1×i,dpi−1,j−1+ai×i)
其中 d p i − 1 , j + a n − ( i − j ) + 1 × i dp_{i - 1,j} + a_{n-(i -j)+1} \times i dpi−1,j+an−(i−j)+1×i 表示从底部拿,因为这是第 i − j i - j i−j 次从底部拿,则拿的是从上往下数第 n − ( i − j ) + 1 n-(i-j)+1 n−(i−j)+1 个, d p i − 1 , j − 1 + a i × i dp_{i-1,j-1} + a_i \times i dpi−1,j−1+ai×i 同理。
注意
d
p
i
,
0
=
d
p
i
−
1
,
0
+
a
n
−
i
+
1
×
i
,
d
p
i
,
i
=
d
p
i
−
1
,
i
−
1
+
a
i
×
i
dp_{i,0} = dp_{i-1,0}+a_{n-i+1} \times i,dp_{i,i} = dp_{i-1,i-1} + a_i \times i
dpi,0=dpi−1,0+an−i+1×i,dpi,i=dpi−1,i−1+ai×i
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,a[2005];
int dp[2005][2005],ans = -1e18;
signed main() {
scanf("%lld",&n);
for(int i = 1;i <= n;i++) scanf("%lld",&a[i]);
for(int i = 1;i <= n;i++) {
dp[i][0] = dp[i - 1][0] + a[n - i + 1] * i;
dp[i][i] = dp[i - 1][i - 1] + a[i] * i;
for(int j = 1;j < i;j++) {
dp[i][j] = max(dp[i - 1][j] + a[n - (i - j) + 1] * i,dp[i - 1][j - 1] + a[j] * i);
}
}
for(int i = 0;i <= n;i++) ans = max(ans,dp[n][i]);
printf("%lld\n",ans);
return 0;
}