题意
输入一个m,n分别表示成m组,一共有n个数即将n个数分成m组,m组的和加起来得到最大值并输出。
思路
状态dp[i][j]表示前j个数分成i组的最大值。
动态转移方程:dp[i][j]=max(dp[i][j-1]+a[j],max(dp[i-1][k])+a[j]) (0 < k < j)
dp[i][j-1]+a[j]表示的是前j-1分成i组,第j个必须放在前一组里面。
max( dp[i-1][k] ) + a[j] )表示的前(0 < k < j)分成i-1组,第j个单独分成一组。
但是题目的数据量比较到,时间复杂度为n^3,n<=1000000,显然会超时,继续优化。
max( dp[i-1][k] ) 就是上一组 0….j-1 的最大值。我们可以在每次计算dp[i][j]的时候记录下前j个的最大值 用数组保存下来 ,这样时间复杂度为 n^2。
dp[ i ] [ j ]也用滚动数组的方法缩小到一维,每次之记录分成i组的最大值和分成i-1组的前j个最大
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#define N 1000010
#define INF 0x7f7f7f7f
using namespace std;
int a[ N ];
int dp[ N ], mx[ N ];
int main () {
int m, n; //组数,点的个数
while ( ~scanf ( "%d%d", &m, &n ) ) {
for ( int i = 1; i <= n; ++i )
scanf ( "%d", &a[ i ] );
memset ( dp, 0, sizeof ( dp ) );
memset ( mx, 0, sizeof ( mx ) );
//滚动数组
int ans;
for ( int i = 1; i <= m; ++i ) { //分成i组
ans = INF;
for ( int j = i; j <= n; ++j ) { //前j个数分成i组
dp[ j ] = max ( dp[ j - 1 ] + a[ j ], mx[ j - 1 ] + a[ j ] );
mx[ j - 1 ] = ans; // 1--j-1分i-1个组的最大
ans = max ( ans, dp[ j ] );
}
}
printf ( "%d\n", ans );
}
return 0;
}