题意:求一个序列中大于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; }