基准时间限制: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;
}