51Nod_1065 最小正子段和
http://www.51nod.com/Challenge/Problem.html#!#problemId=1065
题目
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,是最小的。
输入
第1行:整数序列的长度N(2 <= N <= 50000)。第2 - N+1行:N个整数
输出
输出最小正子段和。
样例输入
8
4
-1
5
-2
-1
2
6
-2
样例输出
1
分析
求出前缀和,然后对前缀和按从小到大排序,值相差最小的一定是相邻的元素,因此只要a[i].val-a[i-1].val>0,且a[i].pos>a[i-1].pos就能更新答案,要a[i].pos>a[i-1].pos是为了保证所求区间的值为正。
C++程序
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll INF=1e18;
const int N=50005;
struct Node{
int pos;
ll val;
//按val值从小到大排序
bool operator<(const Node &a) const
{
return val<a.val;
}
}a[N];
int main()
{
int n;
scanf("%d",&n);
a[0].pos=0;
a[0].val=0;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i].val);
a[i].val+=a[i-1].val;
a[i].pos=i;
}
sort(a,a+n+1);
ll res=INF;
for(int i=1;i<=n;i++)
{
ll tmp=a[i].val-a[i-1].val;
if(a[i].pos>a[i-1].pos&&tmp>0)//跳过tmp=0的情况
res=min(res,tmp);
}
cout<<res<<endl;
return 0;
}