fork download
  1. #include <bits/stdc++.h>
  2.  
  3. using namespace std;
  4.  
  5. typedef long long ll;
  6. typedef pair<int, int> ii;
  7.  
  8. const int INF = 1e9;
  9. const ll LINF = 1e18;
  10.  
  11. template<typename T>
  12. bool minimize(T& a, const T& b) {
  13. if (b < a) {a = b; return true;}
  14. return false;
  15. }
  16.  
  17. // Tối ưu Knuth áp dụng cho các bài DP Range với công thức dp có dạng:
  18. // dp(l, r) = min{dp(l, k) + dp(k + 1, r) + C(l, r)} (l <= k < r)
  19. // Với hàm C thoả mãn các điều kiện sau với mọi a <= b <= c <= d:
  20. // 1. C(b, c) <= C(a, d)
  21. // 2. C(a, c) + C(b, d) <= C(a, d) + C(b, c) (bất đẳng thức tứ giác)
  22. // (Tìm hiểu chi tiết hơn trong phần Tài liệu)
  23. const int N = 5e3 + 5;
  24.  
  25. int n;
  26. int a[N];
  27. ll pref[N];
  28.  
  29. ll getSum(int l, int r) {
  30. return pref[r] - pref[l - 1];
  31. }
  32.  
  33. ll dp[N][N]; // dp[l][r] = Chi phí ít nhất để gộp các phần tử trong đoạn [l, r] về thành 1 phần tử
  34. int opt[N][N]; // opt[l][r] = Điểm k (điểm cắt) tối ưu cho dp[l][r]
  35.  
  36. int main() {
  37. ios::sync_with_stdio(false);
  38. cin.tie(nullptr);
  39. cin >> n;
  40. for (int i = 1; i <= n; i++) {
  41. cin >> a[i];
  42. pref[i] = pref[i - 1] + a[i];
  43. }
  44.  
  45. for (int l = n; l >= 1; l--) {
  46. for (int r = l; r <= n; r++) {
  47. if (l == r) {
  48. dp[l][r] = 0;
  49. opt[l][r] = l;
  50. continue;
  51. }
  52. dp[l][r] = LINF;
  53. for (int k = opt[l][r - 1]; k <= opt[l + 1][r]; k++) {
  54. ll cost = getSum(l, r);
  55. if (minimize(dp[l][r], dp[l][k] + dp[k + 1][r] + cost)) {
  56. opt[l][r] = k;
  57. }
  58. }
  59. }
  60. }
  61.  
  62. cout << dp[1][n] << '\n';
  63. }
Success #stdin #stdout 0s 5644KB
stdin
5
2 7 3 2 5
stdout
43