51nod 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; }
当然也可以归并排序(其实是分治
#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; }