51nod 1065 最小正子段和

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,是最小的。
 
Input
第1行:整数序列的长度N(2 <= N <= 50000)
第2 - N+1行:N个整数
Output
输出最小正子段和。
Input示例
8
4
-1
5
-2
-1
2
6
-2
Output示例
1
———————————————————————————
这道题维护一下前缀和 只要枚举一下区间右端点 然后求前面的比他小的最接近他的就好辣
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#define LL long long
using namespace std;
const int M=50007;
const LL inf=1e15;
int read(){
    LL ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
int n;
LL sum[M],ans=inf;
set<LL>tr;
int main(){
    n=read();
    tr.insert(0);
    for(int i=1;i<=n;i++){    
        sum[i]=sum[i-1]+read();
        set<LL>::iterator it=tr.lower_bound(sum[i]);
        if(it!=tr.begin()) ans=min(ans,sum[i]- *--it);
        tr.insert(sum[i]);
    }printf("%lld\n",ans);
    return 0;
}
View Code

当然也可以归并排序(其实是分治

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#define LL long long
using namespace std;
const int M=50007;
const LL inf=1e15;
int read(){
    LL ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
int n;
LL s[M],ans=inf,c[M];
void merge(int l,int r){
    if(l==r) return ;
    int mid=(l+r)>>1;
    merge(l,mid); merge(mid+1,r);
    int cnt=l,cntl=l,cntr=mid+1;
    while(cntl<=mid&&cntr<=r){
        if(s[cntl]<s[cntr]) ans=min(ans,s[cntr]-s[cntl]),c[cnt++]=s[cntl++];
        else c[cnt++]=s[cntr++];
    }
    while(cntl<=mid) c[cnt++]=s[cntl++];
    while(cntr<=r) c[cnt++]=s[cntr++];
    for(int i=l;i<=r;i++) s[i]=c[i];
}
int main(){
    n=read();
    for(int i=1;i<=n;i++) s[i]=s[i-1]+read();
    merge(0,n);
    printf("%lld\n",ans);
    return 0;
}
View Code

 

 
posted @ 2017-08-28 16:41  友人Aqwq  阅读(165)  评论(0编辑  收藏  举报