• 最小正子段和 贪心


    最小正子段和
    基准时间限制:1 秒 空间限制:131072 KB
    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


    思路:先求出前缀和,然后对前缀和进行排序,排序后求出最大的相邻前缀和之差,并且要满足:相邻前缀和在排序前的位置是递增的。输出这个答案即可

    简单地考虑一下这个算法的正确性:如果没有进行排序,求前后两个前缀和的差的最大值是没有错的,暴力计算需要O(n2)的复杂度,
    排序后,设此时的前缀和为sum[i],每个前缀和对应排序前的位置为p[i],相邻的前缀和如果满足更新条件,即sum[p[i]]>sum[p[i-1]]&&p[i]>p[i-1],
    假设存在一个x<i-1也满足相同条件,我们令p[i]>p[x]>p[i-1]且sum[p[i]]-sum[p[x]]<sum[p[i]]-sum[p[x]],
    即存在与第i个前缀和不相邻的前缀和sum[p[x]],第i个前缀和与第x个前缀和的差值要优于与第i-1的差值,那么就有sum[p[x]]>sum[p[i-1]],但是x<i-1,和排序结果是矛盾的,
    所以不存在x获得排序后第i个前缀和的最优解,即最优解一定是排序后相邻前缀和的差值。

    AC代码:
     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<algorithm>
     5 using namespace std;
     6 typedef long long LL;
     7 const int MAXN=5e4+10;
     8 const LL INF=1e15+10; 
     9 LL sum[MAXN];
    10 int p[MAXN];
    11 bool cmp(int a, int b){
    12     return sum[a]<sum[b];
    13 } 
    14 int main()
    15 {
    16     int n,m;
    17     sum[0]=0;
    18     scanf("%d", &n);
    19     for(int i=0;i<=n;i++) p[i]=i;
    20     for(int i=1;i<=n;i++){
    21         scanf("%d", &m);
    22         sum[i]=sum[i-1]+m;
    23     }
    24     sort(p, p+n+1, cmp);
    25     LL res=INF;
    26     for(int i=1;i<=n;i++){
    27         if(sum[p[i]]-sum[p[i-1]]>0&&p[i]>p[i-1])
    28             res=min(res, sum[p[i]]-sum[p[i-1]]);
    29     }
    30     printf("%lld
    ", res);
    31 }
  • 相关阅读:
    主线程MainThread与渲染线程RenderThread
    杀死进程的几种方式
    Android App的设计架构:MVC,MVP,MVVM与架构经验谈
    动画完全解析(二):补间动画原理及自定义动画
    SublimeText教程
    JqGrid自定义的列
    js 除法 取整
    js日期字符串增加天数的函数
    Oracle中的rownum和rowid
    jQuery判断对象是否是函数
  • 原文地址:https://www.cnblogs.com/MasterSpark/p/7624766.html
Copyright © 2020-2023  润新知