求一个数组的m段的最大子段和。
dp[i][j] 表示 当前是第i段,且最后一个元素是a[j]时的最大子段和。那么有两种转移,作为第i段的最后一个元素 或者 第i段的第一个元素。
状态转移方程为dp[i][j]=max(dp[i][j-1]+a[j],dp[i-1][k]+a[j]) i-1<=k<=j-1
首先必须想到这个。
其次这样的数组必然是开不下,这样递推也必然T。
考虑优化。
dp[i -1][k] 总不至于for一遍算的。考虑用一个一维数组递推代替。
注意到数组的第一维是可以滚动的。
于是优化完毕。
int a[maxn]; int dp[maxn]; int max1[maxn]; int main() { int n, m, tmp; while (~scanf("%d%d", &m, &n)) { for (int i = 0; i <= n; i++) dp[i] = 0, max1[i] = 0; for (int i = 1; i <= n; i++) a[i] = readint(); for (int i = 1; i <= m; i++) { tmp = -INF; for (int j = i; j <= n; j++) { dp[j] = max(dp[j - 1], max1[j - 1]) + a[j]; max1[j - 1] = tmp; tmp = max(tmp, dp[j]); } } Put(tmp); puts(""); } }