基准时间限制: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;
}