[关闭]
@RabbitHu 2017-08-25T03:16:54.000000Z 字数 964 阅读 2565

最大M子段和 | 神奇的DP

题解


题目描述

N个整数组成的序列a[1],a[2],a[3],…,a[n],将这N个数划分为互不相交的M个子段,并且这M个子段的和是最大的。如果M >= N个数中正数的个数,那么输出所有正数的和。
例如:-2 11 -4 13 -5 6 -2,分为2段,11 -4 13一段,6一段,和为26。

Input

第1行:2个数N和M,中间用空格分隔。N为整数的个数,M为划分为多少段。(2 <= N , M <= 5000)
第2 - N+1行:N个整数 (-10^9 <= a[i] <= 10^9)

Output

输出这个最大和

Input示例

7 2
-2
11
-4
13
-5
6
-2

Output示例

26


题解

表示将前个数分成段(且必须以第个数结尾)的最大子段和。


               

其中第二种情况可以处理出那个max,这样时间复杂度就是了。

那么如何压缩空间呢?

外层循环j,内层循环i,用一个pre数组单独维护,一边做一边更新即可。

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <cmath>
  4. #include <algorithm>
  5. #include <iostream>
  6. using namespace std;
  7. typedef long long ll;
  8. const int N = 5005, INF = 0x3f3f3f3f;
  9. int n, m;
  10. ll a[N], dp[N], pre[N];
  11. int main(){
  12. scanf("%d%d", &n, &m);
  13. for(int i = 1; i <= n; i++)
  14. scanf("%lld", &a[i]);
  15. for(int j = 1; j <= m; j++){
  16. dp[1] = a[1];
  17. for(int i = 2; i <= n; i++){
  18. dp[i] = max(dp[i - 1], pre[i - 1]) + a[i];
  19. if(i > 1) pre[i - 1] = max(pre[i - 2], dp[i - 1]);
  20. }
  21. pre[n] = max(pre[n - 1], dp[n]);
  22. }
  23. printf("%lld\n", pre[n]);
  24. return 0;
  25. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注