假设大家都已经写过这道题的原题——最大连续子序列和,我们知道递推方程为 dp[i] = max(nums[i], dp[i - 1] + nums[i])。若 dp[i] = nums[i],说明新起了一段序列;若 dp[i] = dp[i - 1] + nums[i],说明延续了之前序列

如何找到开始下标:在求 dp[i] 的过程中,如果新起了一段序列,那么就说明这是一个潜在的子序列,应该把它的开始下标记录下来。然而,这个子序列并不一定是最大的,因此我们使用变量 t 临时记录该下标,如果等到最后,发现这个子序列是最大的,那才把 t 赋给 firstIndex 作为答案。

如何找到结束下标:在求 dp[i] 的过程中,如果求得的 dp[i] 把 ans 更新了(意味着该段序列最大),那么就把 i 赋值给 lastIndex 作为答案。


代码(很容易读懂):
#include <iostream>
#include <cstdio>
using namespace std;

const int MAXN = 10005;

int nums[MAXN];
int dp[MAXN];

int main() {
    int n;
    while (scanf("%d", &n) != EOF) {
        if (n == 0) {
            break;
        }
        
        bool allNegative = true;
        for (int i = 0; i < n; i++) {
            scanf("%d", &nums[i]);
            if (nums[i] >= 0) {
                allNegative = false;
            }
        }
        if (allNegative) {
            printf("0 %d %d\n", nums[0], nums[n - 1]);
            continue;
        }
        
        dp[0] = nums[0];
        int ans = dp[0], firstIndex = 0, lastIndex = 0, t = 0;
        for (int i = 1; i < n; i++) {
            if (nums[i] > dp[i - 1] + nums[i]) {  // 新起一段序列
                dp[i] = nums[i];
                t = i;
            } else {  // 延长之前序列
                dp[i] = dp[i - 1] + nums[i];
            }
            
            // 如果把ans更新了,才真正找到了满足题意的最大连续子序列
            if (dp[i] > ans) {
                ans = dp[i];
                firstIndex = t;
                lastIndex = i;
            }
        }
        printf("%d %d %d\n", ans, nums[firstIndex], nums[lastIndex]);
    }
    return 0;
}