原题链接



1052 最大M子段和



基准时间限制:2 秒 空间限制:131072 KB 分值: 80  难度:5级算法题



 收藏

 关注

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-211-4 13 -5 6 -2


Output示例


26


用dp[i][j]表示以i结尾的数组被分为j段的最大和(第j个数字一定要用) dp[i][j] = max(dp[i-1][j], d) + num[j], 其中d = max(dp[h][j-1]) h < i

因为空间限制,要用滚动数组


#include <bits/stdc++.h>
#define MOD 1000000007
#define maxn 5005
#define INF 1e18
using namespace std;
typedef long long ll;

int num[maxn];
ll dp[maxn][2];
int main(){
//	freopen("in.txt", "r", stdin);
	ll p = 0;
	int n, m, k = 0;
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++){
		scanf("%d", num+i);
		if(num[i] > 0){
			k++;
			p += num[i];
		}
	}
	if(m >= k){
		printf("%I64d\n", p);
		return 0;
	}
	int e = 1;
	for(int i = 1; i <= m; i++){
	 ll d = dp[0][e^1];
	 for(int j = 1; j <= n; j++){
	 	dp[j][e] = max(dp[j-1][e], d) + num[j];
	 	d = max(d, dp[j][e^1]);
	 }
	 for(int j = 0; j < i; j++)
	  dp[j][e] = -INF;
	 e ^= 1;
    }
	ll maxs = 0;
	for(int i = 0; i <= n; i++){
	 maxs = max(maxs, dp[i][e^1]);
   }
	cout << maxs << endl;
	return 0; 
}