51nod-1065:最小正子段和(STL)

N个整数组成的序列a 11,a22,a33,…,ann,从中选出一个子序列(aii,ai+1i+1,…ajj),使这个子序列的和>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 Input

8
4
-1
5
-2
-1
2
6
-2

Sample Output

1

思路:对于每个前缀和,找到左边的u最大的小于sum[i]的数,两种写法:

第一种手动维护有序数列。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=50010;
ll a[maxn];
vector<ll>v;
int main()
{
    ll N,i,j,ans=-1;
    scanf("%lld",&N);
    v.push_back(0);
    for(i=1;i<=N;i++){
        scanf("%lld",&a[i]);
        a[i]+=a[i-1];
        int pos=lower_bound(v.begin(),v.end(),a[i])-v.begin();
        if(pos-1>=0&&(ans==-1||ans>a[i]-v[pos-1])) ans=a[i]-v[pos-1];
        pos=upper_bound(v.begin(),v.end(),a[i])-v.begin();
        v.insert(v.begin()+pos,a[i]);
    }
    printf("%lld\n",ans);
    return 0;
}

第二种用lower_bound+set

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll inf=1e18;
const int maxn=50010;
ll a[maxn];
set<ll>s;
int main()
{
    ll N,i,j,ans=inf;
    scanf("%lld",&N);
    for(i=1;i<=N;i++){
        scanf("%lld",&a[i]);
        a[i]+=a[i-1];
    }
    s.insert(a[N]);
    for(i=N-1;i>=0;i--){
        ll t=*s.lower_bound(a[i]+1);
        if(t-a[i]>0) ans=min(ans,t-a[i]);
        s.insert(a[i]); 
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hua-dong/p/9139378.html