题意: 从长度为n的数组中取出m段不相交的子段,求取出子段的最大和。
题解: 先思考只取一段的最大值问题,很容易能想出定义状态dp[i]
表示第i位的最值问题,其状态转移方程为dp[i[ = max(dp[i - 1] + s[i], s[i])
。但问题在于我们需要取出m个子段。我们可以按照先计算只取一段的最值,然后再思考取两端的最大和,逐步递推,直到取出m段。
定义一个数组lmax[i]
表示到i为止能取到的最大和,从而状态转移方程变为dp[i] = max(dp[i - 1], lmax[i - 1]) + s[i];
。至于我们需要取m个子段,则需要每次更新lmax数组以后,重新更新dp数组表示增加一个子段情况的最大和问题。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, m, maxx;
int s[N], dp[N], lmax[N];
int main(){
while(~scanf("%d%d", &m, &n)){
memset(dp, 0, sizeof dp);
memset(lmax, 0, sizeof lmax);
for(int i = 1; i <= n; i++) scanf("%d", s + i);
for(int i = 1; i <= m; i++){
for(int j = i; j <= n; j++)
dp[j] = max(dp[j - 1], lmax[j - 1]) + s[j];
maxx = -0x3f3f3f;
for(int j = i; j <= n; j++)
lmax[j] = maxx = max(maxx, dp[j]);
}
printf("%d\n", maxx);
}
return 0;
}