51nod-1065:最小正子段和(STL)
N个整数组成的序列a11,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; }
It is your time to fight!