NOIP 2006 能量项链
思路
简单的区间 dp , 显然 \(dp[i][j]\) 表示从 \(i\) 一直聚合到 \(j\) .
再枚举断点 \(k(1\leq k < j)\) , 考虑合并 \(dp[i][k]\) 和 \(dp[k + 1][j]\) , 显然最终答案里包含 \(dp[i][k] + dp[k + 1][j]\).
令 \(a[i][0]\) 表示 \(i\) 的头标记, \(a[i][1]\) 表示 \(i\) 的尾标记.
再考虑聚合后的额外收益为 \(m \times r \times n\) 即 \(a[i][0] \times a[k][1] \times a[j][1]\)
综上得 \(dp[i][j] = \mathop{max\{dp[i][k] + dp[k + 1][j] + a[i][0] \times a[k][1] \times a[j][1]\}}\limits_{1 \leq k < j}\)
注意:
- 初始时有 \(dp[i][i] = 0(1 \leq i \leq 2n)\)
- 破环为链
代码
剩下的看代码吧:
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read() {
int x = 0; char c = getchar(); bool f = 1;
while(c < '0' || c > '9') { if(c == '-') f = 0; c = getchar(); }
while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return (f ? x : -x);
}
const int N = 1e3 + 10;
int n, res, a[N][2], dp[N][N];
signed main() {
n = read();
for(int i = 1; i <= n; ++i) {
a[i - 1][1] = a[i][0] = read();
if(i == n) a[i][1] = a[1][0];
}
for(int i = 1; i <= n; ++i) {
a[i + n][0] = a[i][0];
a[i + n][1] = a[i][1];
}
for(int l = 1; l < n; ++l) {
for(int i = 1; i <= (n << 1); ++i) {
int j = i + l;
for(int k = i; k < j; ++k) {
dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j] + a[i][0] * a[k][1] * a[j][1]);
}
res = max(res, dp[i][j]);
}
}
printf("%lld\n", res);
return 0;
}