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