51nod-1065 最小正子段和

基准时间限制:1 秒 空间限制:131072 KB 分值: 20  难度:3级算法题
 收藏
 关注
N个整数组成的序列a[1],a[2],a[3],…,a[n],从中选出一个子序列(a[i],a[i+1],…a[j]),使这个子序列的和>0,并且这个和是所有和>0的子序列中最小的。
例如:4,-1,5,-2,-1,2,6,-2。-1,5,-2,-1,序列和为1,是最小的。
Input
第1行:整数序列的长度N(2 <= N <= 50000)
第2 - N+1行:N个整数
Output
输出最小正子段和。
Input示例
8
4
-1
5
-2
-1
2
6
-2
Output示例
1

题解:暴力做法,得到所有连续序列的和,求大于0的最小值,O(n ^2),果断 TLE;

我们假设最小和的起点为i位置,终点在r位置,则对于前缀和数组p[maxn], p[j] - p[i - 1] >= p[r] - p[i - 1](j >= i),故对于以i为起点的元素,只需要获得编号比i大且和最小的(大于p[i - 1])即可,故我们可以先按和升序,最小和只可能在相邻前缀和间(注意先对前缀和求最小正和再取相邻合法差的最小正和)

AC代码

#include <stdio.h>
#include <iostream>
#include <string>
#include <queue>
#include <map>
#include <vector>
#include <algorithm>
#include <string.h>
#include <cmath>
typedef long long ll;

using namespace std;

const ll maxn = 55555, inf = 1e18;

struct node{
	ll id, val;
}p[maxn];

bool cmp(node a1, node a2){
	return a1.val < a2.val;
}

int main(){
	ll n, t;
	scanf("%lld", &n);
	ll ans = inf;
	for(ll i = 0; i < n; i++){
		scanf("%lld", &t);
		p[i].val = (i == 0 ? t: p[i - 1].val + t);
		p[i].id = i;
		if(p[i].val > 0)
			ans = min(ans, p[i].val);
	}
	sort(p, p + n, cmp);
	for(ll i = 0; i < n - 1; i++)
		if(p[i + 1].id > p[i].id && p[i + 1].val > p[i].val)
			ans = min(p[i + 1].val - p[i].val, ans);
	printf("%lld\n", ans);
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_37064135/article/details/80010810