最小正子段和(前缀和+思维)

最小正子段和

基准时间限制:1 秒 空间限制:131072 KB 

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

分析:最近打牛客网的练习赛碰到一个和这个有点关系的题目,只能想到前缀和,后面就没了思路,队友告诉我和这个有点像,所以决定写一下,觉得写过的很多类似的题;
N的取值范围为2 <= N <= 50000,所以暴力肯定会超时,所以我们用前缀和!但不是一般的前缀和,我们定义一个结构体,一个变量用来存储前缀和,一个变量用来存储下标,按前缀和排序,后面的比较就是个思维了!仔细想想,排序后,一个数字只有和它相邻数的差或者它本身为最小值,代码还是很好写的!
AC代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 50050
typedef long long ll;
using namespace std;
struct point
{
    ll w;
    int v;
}b[N];
int a[N];
bool cmp(point x,point y)
{
    return x.w<y.w;
}
int main()
{
    int n;
    cin>>n;
    for (int i=1;i<=n;i++)
    cin>>a[i];
    b[1].w=a[1];
    for (int i=2;i<=n;i++)
    {
        b[i].w=b[i-1].w+a[i];
        b[i].v=i;
    }
    sort(b+1,b+1+n,cmp);
    ll ans;
    if (b[1].w>0)  ans=b[1].w;
    else ans=99999999;
    for (int i=2;i<=n;i++)
    {
        if (b[i].w>0&&b[i].w<ans)
          ans=b[i].w;
        if (b[i].w>b[i-1].w&&b[i].v>b[i-1].v&&(b[i].w-b[i-1].w<ans))
          ans=b[i].w-b[i-1].w;
    }
    cout << ans << endl;
    return 0;
}
 
原文地址:https://www.cnblogs.com/lisijie/p/8362672.html