NOIP 2006 能量項鍊
阿新 • • 發佈:2022-05-16
思路
簡單的區間 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; }