东大OJ-最大子序列问题的变形

时间:2022-01-28 04:00:39

1302: 最大子序列

时间限制: 1 Sec  内存限制: 128 MB

提交: 224  解决: 54

[提交][状态][讨论版]

题目描述

给定一个N个整数组成的序列,整数有正有负,找出两段不重叠的连续子序列,使得它们中整数的和最大。两段子序列都可以为空。

输入

多组输入,每组第一行为N,表示序列的长度;第二行为N个整数(-1000<=n<=1000),表示输入序列。
0<N<=1,000,000

输出

对于每组输入,输出一行,仅一个整数,表示最大的和。

样例输入

9
185 -580 -889 701 964 -878 353 -761 608

样例输出

2273
第一步,求出最大子序列M;M表示max
第二步,求出不与M相交的第二大子序列S;S表示second
第三步,求出M中的最小子序列L;L表示little
最后,分两种情况:M+S或者是M一分为二;
若S+L<0,说明L太小了,M应该舍弃L,一分为二;
否则,M+=S;
#include<iostream>
using namespace std;
int a[1000007];
int m[1000007];
int from, to;
int M, S, L;
int n;
void init(){
	int i;
	M = 0;
	m[0] = a[0];
	int f, t;
	f = t = 0;
	for (i = 1; i < n; i++)
	{
		if (m[i - 1]>0){
			m[i] = m[i - 1] + a[i];
			t++;
		}
		else{
			f = t = i;
			m[i] = a[i];
		}
		if (M < m[i]){
			M = m[i];
			from = f;
			to = t;
		}
	}
}
void getS(){
	int i;
	int mm = 0;
	for (i = 0; i < from; i++){
		if (m[i]>mm)
			mm = m[i];
	}
	int now = a[to + 1];
	for (i = to + 2; i < n; i++){
		if (now>0){
			now += a[i];
		}
		else{
			now = a[i];
		}
		if (now > mm)mm = now;
	}
	S = mm;
}
void getL(){
	int i;
	int ll = a[from];
	int now = a[from];
	for (i = from + 1; i < to + 1; i++){
		if (now<0){
			now += a[i];
		}
		else{
			now = a[i];
		}
		if (now < ll)ll = now;
	}
	L = ll;
}
int main(){
	freopen("in.txt", "r", stdin);
	while (scanf("%d", &n) != -1){
		int i;
		for (i = 0; i < n; i++){
			scanf("%d", &a[i]);
		}
		init();
		getS();
		getL();
		if (S + L < 0){
			M -= L;
		}
		else{
			M += S;
		}
		printf("%d\n", M);
	}
	return 0;
}