[51nod1065]最小正子段和

 题意:求一个序列中大于0的最小子段和。

解题关键:

先求出前缀和和,对于每个位置求某个位置到当前位置和大于1的和的最小值。然而这是复杂度是O(n^2)的。其实可以通过排序优化到O(nlogn)。对前缀和排序,且对于每个值记录索引的最大值和最小值。然后看相邻两个数是否可以组成最小正序列。

具体为什么只需求相邻两个数,这引用夹克老爷的话:解释一下为什么只需检查相邻2个数就可以,设ABC是排序后的结果,如果A同B不能组成序列,而A同C可以组成序列,那么B同C也可以组成序列,并且BC会是一个更优的解。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[50002];
struct node{
    ll sum,idx;
}nn[50002];
const ll inf=1ll<<61;
bool cmp(const node &a,const node &b){
    return a.sum<b.sum||(a.sum==b.sum&&a.idx<b.idx);
}
int main(){
    ll n,ans=inf;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i],nn[i].sum=nn[i-1].sum+a[i],nn[i].idx=i;
    sort(nn,nn+n+1,cmp);
    for(int i=1;i<=n;i++){
        if(nn[i].sum>0){
            ans=min(ans,nn[i].sum);
        }
        if(nn[i].sum>nn[i-1].sum&&nn[i-1].idx<nn[i].idx){
            ans=min(ans,nn[i].sum-nn[i-1].sum);
        }
    }
    cout<<ans<<"
";
    return 0;
}
原文地址:https://www.cnblogs.com/elpsycongroo/p/7782120.html