solution
找到最大连续子序列和,并返回对应方案的首尾元素,若有多组则返回下标最小的组。若最大子序列和为负数,规定最大和为0,返回整个序列的首尾元素。
状态dp[i]是以a[i]为结尾的最大子序列和,状态转移方程为dp[i] = max(a[i], dp[i-1] + a[i])
。
p[i]记录以a[i]为结尾的方案起始元素坐标或者直接用l,r两个坐标维持当前方案边界。
注意的是,方案选择上判断的是元素下标,而需要输出的是元素值。
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 10010;
int a[maxn], dp[maxn], p[maxn] = {0};//a[i]存放序列,dp[i]存放以a[i]为结尾的连续序列的最大和
int main(){
int n, ans, ansp = 0;
scanf("%d", &n);
for(int i = 0; i < n; i++)//读入序列
scanf("%d", &a[i]);
ans = dp[0] = a[0];//边界
for(int i = 1; i < n; i++){
if(a[i] > dp[i - 1] + a[i]) p[i] = i;
else p[i] = p[i - 1];
dp[i] = max(a[i], dp[i - 1] + a[i]);//状态转移方程
if(dp[i] > ans) {
ans = dp[i];
ansp = i;
}
}
if(ans < 0) printf("0 %d %d", a[0], a[n - 1]);
else printf("%d %d %d", ans, a[p[ansp]], a[ansp]);
return 0;
}
或者
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 10010;
int a[maxn], dp[maxn];//a[i]存放序列,dp[i]存放以a[i]为结尾的连续序列的最大和
int main(){
int n, ans, ansp = 0, l = 0, r = 0, cur;
scanf("%d", &n);
for(int i = 0; i < n; i++)//读入序列
scanf("%d", &a[i]);
ans = dp[0] = a[0];//边界
for(int i = 1; i < n; i++){
if(a[i] > dp[i - 1] + a[i]) cur = i;
dp[i] = max(a[i], dp[i - 1] + a[i]);//状态转移方程
if(dp[i] > ans) {
ans = dp[i];
l = cur;
r = i;
}
}
if(ans < 0) printf("0 %d %d", a[0], a[n - 1]);
else printf("%d %d %d", ans, a[l], a[r]);
return 0;
}