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;
}

原文地址:https://www.cnblogs.com/hua-dong/p/9139378.html

时间: 2024-11-29 02:10:44

51nod-1065:最小正子段和(STL)的相关文章

51nod 1065 最小正子段和

题目链接:51nod 1065 最小正子段和 房教说用前缀和做,然后看了别人博客懂了后就感觉,这个真有意思... 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N = 50001; 6 const int inf = 0x3f3f3f3f; 7 pair<long long, int> sum[N]; 8 int

51nod 1065 最小正子段和 (贪心)

题目:传送门. 题意:中文题. 题解:求前缀和,并且标记每个数的下标,按照前缀和大小进行从小到大排序.随后进行遍历,如果满足下标data[i-1].id<data[i].id&&data[i-1].val<data[i].val:就更新最小值,因为是相近的,所以已经是最小值候选了,其余的绝对不可能了.那么为什么只考虑相邻的呢?因为如果A到B不能形成队列,A到C形成队列了,那么B到C一定是比A到C的数值更小,而且还一定能够形成队列(A与B不能形成队列,说明posA>posB

1065 最小正子段和 二分答案 + 判定

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1065 我的思路比较笨,我是直接二分那个答案mid 然后进行一次O(nlogn)的判定,如果能找到一个区间的和比mid小的,(当然这个区间的和也是要大于0),那就return true 进行判断如下: 处理出前缀和dp[i],对于每一个i 目标是:在前i - 1个中,查看是否有这样的一个x,使得,dp[i] - x    <=   mid,&& dp[i] -

【瞎搞】 51nod 1065 最小正字段和

通道 思路:先求一下从第一位开始的到第i位的累加,4,-1,5,-2,-1,2,6,-2 => 4 3 8 6 5 7 13 11 对这个累加的数列排个序,然后只要判断邻近的两个数是否可以组成序列,比如4和3就不可以,因为4 > 3而4对应下标为0,3对应为1.4和5就可以,然后相同的前缀和取id最小,一开始丢个(0,0)进去. 代码: #include <cstdio> #include <cstring> #include <algorithm> usi

AC日记——最小正子段和 51nod 1065

最小正子段和 思路: 找最小的大于0的sum[j]-sum[i](j>i): 高级数据结构(splay)水过: 来,上代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 50005 #define ll long long #define INF 0x7fffffff str

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示

最小正子段和

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 思路: 虽然说

[51nod1065]最小正子段和

#include<bits/stdc++.h> using namespace std; typedef long long ll; ll a[50002]; struct node{ ll sum,idx; }nn[50002]; const ll inf=1ll<<61; bool cmp(const node &a,const node &b){ return a.sum<b.sum||(a.sum==b.sum&&a.idx<b.

51Node 1065----最小正子段和

51Node  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