题意:在o(n)时间内,求最大连续的子序列的和最大,及其起点和终点。
数据:输入以及输出
方法一:一边读取数据一边维护最小前缀和S[i],然后不断更新ans,ans=max(ans,s[i]-s[k]),以及初始位置st,en;
代码:
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=100010;
int s[maxn];
int main()
{
int cun=1;
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
int k=0;
int st,en;
int num;
int a[maxn];
s[0]=0;
int ans=-1001;
for(int i=1;i<=n;i++)
{
scanf("%d",&num);
s[i]=s[i-1]+num;
if(s[i]-s[k]>ans)
{
ans=s[i]-s[k];
en=i;
st=k+1;
}
if(s[i]<s[k]){
k=i;
}
}
printf("Case %d:\n%d %d %d\n",cun,ans,st,en);
cun++;
}
return 0;
}
代码下的运行过程分析(第一组数据):
i | s[i] | k | s[k] | ans | st | en |
0 | 0 | 0 | 0 | -1001 | 0 | 0 |
1 | 6 | 0 | 0 | 6 | 1 | 1 |
2 | 5 | 0 | 0 | 6 | 1 | 1 |
3 | 10 | 0 | 0 | 10 | 1 | 3 |
4 | 14 | 0 | 0 | 14 | 1 | 4 |
5 | 7 | 0 | 0 | 14 | 1 | 4 |
再分析一组数据:5 5 -7 4 6 -1 输出结果为:10 3 4
i | s[i] | k | s[k] | ans | st | en |
0 | 0 | 0 | 0 | -1001 | 0 | 0 |
1 | 5 | 0 | 0 | 5 | 1 | 1 |
2 | -2 | 2 | -2 | 5 | 1 | 1 |
3 | 2 | 2 | -2 | 5 | 1 | 1 |
4 | 8 | 2 | -2 | 10 | 3 | 4 |
5 | 7 | 2 | -2 | 10 | 3 | 4 |
从这两组数据分析中并结合实际可以分析出s[k]是用来调和新的可能最大的连续子序列,由于s[i]是由s[i-1]+a递推过来的,所以当s[i]<s[k]时k=i;s[i]-s[k]可以还原由于递推过来重新开始时最初那个数据的缺失,例如,第二次数据分析中i=3时a原本是4的,但却由于s[i]=s[i-1]+a变成了2,所以再执行s[i]-s[k]把i=3的a从2还原成4,s[k]的作用就在于此。