当前位置: 代码迷 >> 综合 >> 【51nod-1065】最小正子段和(思维)
  详细解决方案

【51nod-1065】最小正子段和(思维)

热度:65   发布时间:2023-12-06 19:37:13.0

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,是最小的。

 收起

输入

第1行:整数序列的长度N(2 <= N <= 50000)
第2 - N+1行:N个整数

输出

输出最小正子段和。

输入样例

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

输出样例

1

思路:

先求一遍前缀和,然后对于一个数想办法找他后面的数中大于他的最小值,他俩的差值就是结果。这里用到set,倒着扫,对一个数先用upper_bound找set中大于他的最小的元素,因为倒着扫的,所以这些元素都保证在他后面,找到他俩的差值与最优解做比较赋值给最优解。注意数组从1开始读,要倒着枚举要枚举0元素。因为枚举0号代表数组从头选,否则就会少了这一点。

ac代码:

#include<bits/stdc++.h>
#include<set>
using namespace std;
typedef long long ll;
const int maxn=50010;
ll a[maxn];
set<ll> ss;
set<ll> ::iterator it;
int main(){int n;cin>>n; for(int i=1;i<=n;i++){scanf("%lld",&a[i]);a[i]+=a[i-1];}ll ans=0x3f3f3f3f;for(int i=n;i>=0;i--){it=ss.upper_bound(a[i]);ss.insert(a[i]);if(it!=ss.end()){ans=min(ans,*it-a[i]);}}printf("%lld\n",ans);return 0;
}