最大连续子序列和
题目分为两步,第一步求最大和,第二步求该子序列的起始点和结束点。
首先看第一步
求子序列的最大和
定义一个sum,表示从头开始到当前位置序列之和,若sum<0,则将sum置为0,并更新答案.
这里有dp的思想,即无需管sum之前是怎么来的,只要管当前序列的值与sum的和,从而推出下一个sum。
这样一遍遍历就可以得到最大和。
接下来第二步,如何定位子序列的起始点和结束点。
结束点很好定位,在更新最大值时顺便更新即可,起始点稍微有点复杂。
首先我们考虑,起始点是从第一个开始的,然后当在i位置sum<0时,起始点就要更新为i+1,因为前缀和是负数,肯定不能取,一定要从他后面开始,sum置0也是同理。但是不能每次碰到sum<0时就更新,这样会越过最大值的位子。
那么在什么时候更新呢,我们想到了,既然与最大值的位置有关,那在更新最大值时更新起始点位置不就好了吗,我们用一个临时变量来记录可能的起始点的位置,在最大值更新时,更新起始点的值。
代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
int main()
{
long long n;
long long a[10005];
long long sum=0;
long long maxn,maxp,minp;
bool flag=0;
while(~scanf("%lld",&n))
{
memset(a,0,sizeof(a));
flag=0;
minp=1;
int tempp=1;
sum=0;
long long cnt=0;
scanf("%lld",&a[1]);
if(a[1]>=0) flag=1;
sum+=a[1];
maxn=sum;
maxp=1;
if(sum<0)
{
sum=0;
tempp=2;
maxp=2;
minp=2;
}
for(int i=2;i<=n;i++)
{
scanf("%lld",&a[i]);
if(a[i]>=0) flag=1;
sum+=a[i];
if(sum<0)
{
sum=0;
tempp=i+1;
}
if(sum>maxn)
{
maxn = sum;
minp= tempp;
maxp =i;
}
}
if(!flag)
{
printf("0 %lld %lld\n",a[1],a[n]);
continue;
}
printf("%lld %lld %lld\n",maxn,a[minp],a[maxp]);
}
return 0;
}