fork download
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. using ll = long long;
  4.  
  5. const ll INF = (1LL<<60);
  6.  
  7. int n, m;
  8. vector<ll> prefix;
  9. vector<ll> pre_dp, cur_dp;
  10.  
  11. // cost của đoạn [l..r]
  12. inline ll C(int l, int r) {
  13. ll sum = prefix[r] - (l>0 ? prefix[l-1] : 0);
  14. ll len = r - l + 1;
  15. return sum * len;
  16. }
  17.  
  18. void compute(int l, int r, int optl, int optr) {
  19. if (l > r) return;
  20. int mid = (l + r) >> 1;
  21. pair<ll,int> best = {INF, -1};
  22. for (int k = optl; k <= min(mid, optr); ++k) {
  23. ll val = (k ? pre_dp[k-1] : 0) + C(k, mid);
  24. if (val < best.first) {
  25. best = {val, k};
  26. }
  27. }
  28. cur_dp[mid] = best.first;
  29. int opt = best.second;
  30. compute(l, mid-1, optl, opt);
  31. compute(mid+1, r, opt, optr);
  32. }
  33.  
  34. int main(){
  35. ios::sync_with_stdio(false);
  36. cin.tie(nullptr);
  37.  
  38. // n = số ô, m = số guard
  39. cin >> n >> m;
  40. prefix.resize(n);
  41. for (int i = 0; i < n; i++) {
  42. ll x;
  43. cin >> x;
  44. prefix[i] = x + (i>0 ? prefix[i-1] : 0);
  45. }
  46.  
  47. // DP khởi tạo: chỉ 1 guard -> toàn bộ prefix [0..i]
  48. pre_dp.assign(n, 0);
  49. for (int i = 0; i < n; i++) {
  50. pre_dp[i] = C(0, i);
  51. }
  52.  
  53. // Chia m guard thành m nhóm liên tiếp
  54. for (int g = 1; g < m; g++) {
  55. cur_dp.assign(n, INF);
  56. compute(0, n-1, 0, n-1);
  57. pre_dp = cur_dp;
  58. }
  59.  
  60. cout << pre_dp[n-1] << "\n";
  61. return 0;
  62. }
  63.  
Success #stdin #stdout 0.01s 5320KB
stdin
6 3
11
11
11
24
26
100
stdout
299