最小正子段和
N个整数组成的序列a1,a2,a3,…,an,从中选出一个子段(ai,ai+1,…aj
),使这个子段的和>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输出最小正子段和。Sample Input8 4 -1 5 -2 -1 2 6 -2
首先处理出前缀和数组。在前缀和数组中,我们要求的是dmin=sum[i]-sum[j](当 i>j && sum[i]-sum[j]>0 时)。
那么就可以用一个新的结构体来存储每个sum[i]和它的编号。即 b[i].id=i; b[i].w=sum[i];
此时sort之后我们就有了一个按照 前缀和大小 排序的带有顺序的结构体。
之后再用一个循环去挨个遍历找相邻连个的最下差值。
注意当 b[i].w==b[j].w 的时候,我们要让 id 大的在前面。这样的话,当有很多前缀和都相等的时候,比如 2 3 3 3 3 3 3 4,就避免了许多不必要的比较。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> const int MAXN = 50000+3; using namespace std; typedef long long ll; int n,Min; ll a[MAXN],sum[MAXN],ans; struct B{int id;ll w;}b[MAXN]; bool Com(B x,B y){ if(x.w==y.w) return (x.id>y.id); return (x.w<y.w); } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%lld",&a[i]); b[i].w=sum[i]=sum[i-1]+a[i]; b[i].id=i; } sort(b+1,b+1+n,Com); if(b[1].w>0) ans=b[1].w;//注意不要忽略以a[1]开头的一段区间!!! else ans=0x3f3f3f3f3f3f3f3f; for(int i=2;i<=n;i++){ int d=b[i].w-b[i-1].w; if(b[i].w>0 && ans>b[i].w) ans=b[i].w;//注意不要忽略以a[1]开头的一段区间!!! if(b[i].id>b[i-1].id && d>0 && ans>d){ ans=(ll)b[i].w-b[i-1].w; } } printf("%lld",ans); return 0; }