[ifrog 1074 Pick Up Coins] 区间DP
1. 题目链接
2. 题意描述
n
个硬币,第
假定
3≤n≤103
。
3. 解题思路
用
dp[i][j]
表示区间
[i,j]
中能够获得最大价值。那么可以写出转移方程:
dp[i][j]=max{dp[i][k−1]+dp[k+1][j]+vi−1∗vk∗vj+1}
4. 实现代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int MAXN = 1e3 + 5;
const int INF = 0x3f3f3f3f;
const LL INFL = 0x3f3f3f3f3f3f3f3fLL;
int n;
LL a[MAXN];
LL dp[MAXN][MAXN];
/**
暴力查错
void del(vector<LL>& L, vector<LL>& R, int x) {
L[R[x]] = L[x];
R[L[x]] = R[x];
}
LL special(int s, int sz) {
vector<LL> b(sz + 2), L(sz + 2), R(sz + 2), gen(sz);
b[0] = b[sz + 1] = 1;
for(int i = 0; i < sz; i++) {
gen[i] = i + 1;
b[i + 1] = a[i + s];
}
LL ret = 0;
do{
for(int i = 0; i <= sz + 1; i++) L[i] = i - 1, R[i] = i + 1;
LL val = 0;
for(int i = 0; i < sz; i++) {
LL id = gen[i];
val += b[L[id]] * b[id] * b[R[id]];
del(L, R, id);
}
ret = max(ret, val);
}while(next_permutation(gen.begin(), gen.end()));
return ret;
}
*/
void solve() {
memset(dp, 0, sizeof(dp));
a[0] = a[n + 1] = 1;
dp[0][0] = dp[n + 1][n + 1] = 1;
for(int i = 1; i <= n; i++) {
dp[i][i] = a[i - 1] * a[i] * a[i + 1];
}
for(int len = 2; len <= n; len++) {
for(int i = 1; i + len - 1 <= n; i++) {
int j = i + len - 1;
for(int k = i; k <= j; k++) {
LL v = dp[i][k - 1] + dp[k + 1][j] + a[i - 1] * a[k] * a[j + 1];
if(dp[i][j] < v) dp[i][j] = v;
}
}
}
}
int main() {
#ifdef ___LOCAL_WONZY___
freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
int _;
scanf("%d", &_);
while(_ --) {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
}
solve();
printf("%lld\n", dp[1][n]);
// printf("%lld\n", special(1, n));
}
return 0;
}