题意: 给出n个数字a(i),每次你可以取出最左边的数字或者取出最右边的数字,一共取n次取完。假设你第i次取的数字是x,那么你可以获得i*x的价值。现在你需要规划取数顺序,使得总价值和最大。
思路:
dp[k][i]
d
p
[
k
]
[
i
]
表示第
k
k
次取,左边取到了位置的最大值,那么右边也就取到
j=n−(k−i)
j
=
n
−
(
k
−
i
)
。
dp[k][i]
d
p
[
k
]
[
i
]
可以由两种状态转移过来:
①上一次取了最左边,
dp[k−1][i−1]+a[i−1]∗(k−1),(1≤i≤k)
d
p
[
k
−
1
]
[
i
−
1
]
+
a
[
i
−
1
]
∗
(
k
−
1
)
,
(
1
≤
i
≤
k
)
②上一次取了最右边,
dp[k−1][i]+a[j+1]∗(k−1),(1≤i≤k)
d
p
[
k
−
1
]
[
i
]
+
a
[
j
+
1
]
∗
(
k
−
1
)
,
(
1
≤
i
≤
k
)
所以:
dp[k][i]=max(dp[k−1][i−1]+a[i−1]∗(k−1),dp[k−1][i]+a[j+1]∗(k−1)),(1≤i≤k)
d
p
[
k
]
[
i
]
=
m
a
x
(
d
p
[
k
−
1
]
[
i
−
1
]
+
a
[
i
−
1
]
∗
(
k
−
1
)
,
d
p
[
k
−
1
]
[
i
]
+
a
[
j
+
1
]
∗
(
k
−
1
)
)
,
(
1
≤
i
≤
k
)
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 2005;
int n, a[MAXN], dp[MAXN][MAXN];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
int MAX = 0;
for (int k = 1; k <= n+1; k++)
{
for (int i = 1; i <= k; i++)
{
int j = n-(k-i);
dp[k][i] = max(dp[k-1][i-1]+a[i-1]*(k-1), dp[k-1][i]+a[j+1]*(k-1));
MAX = max(MAX, dp[k][i]);
}
}
printf("%d\n", MAX);
return 0;
}
/*
5
1 3 1 5 2
*/