• 循环数组最大子段和(带限制的最大子段和,单调队列优化)


    题目链接:here

     

     
    题解:对于不带限制的最大字段和我们可以:求一遍前缀和,求出最大值最小值,最后结果 res = max( MAX,  SUM - MIN );
    那么对于这道题相当于带了限制:限制最大子段的长度是len:我们可以维护一个前缀和 ,然后结果就是 max( sum[i] - min(sum[j]) ), i-len <= j <= i-1 && 1<=i <= 2*n,注意这里j>=i-len,而不是i-len+1,因为前缀和相减的时候要注意会把j位置上的那个数也减去)。然后这么看来 是n^2的dp,那么如何优化呢。
    可以预处理  长度为len的区间的最小值  然后对于每个i 查询前面区间长度为 len 的最小值 然后 sum[i] - sum[j]即可
    我们可以维护一个单调队列,单调队列要满足两点:
    • 队内元素的位置 要符合 (i)的区间要求 即 i-len <=que[j]<=i-1
    • 单调性,队列内的元素 尽可能小(因为我们要减去最小值呀),维护一个单调非递减队列(递增或持平)

    AC_Code:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxn = 1e6+10;
     5 const ll inf = 0x3f3f3f3f3f3f3f3f;
     6 deque<ll>q;
     7 ll a[maxn];
     8 ll n,m;
     9 ll sum[maxn];
    10 
    11 int main()
    12 {
    13     scanf("%lld",&n);
    14     for(ll i=1;i<=n;i++){
    15         scanf("%lld",&a[i]);
    16         sum[i] = sum[i-1]+a[i];
    17     }
    18     for(ll i=n+1;i<=2*n;i++){
    19         a[i] = a[i-n];
    20         sum[i] = sum[i-1]+a[i];
    21     }
    22     m = n;
    23     n<<=1;
    24 
    25     while( !q.empty() ) q.pop_front();
    26     ll res = 0;
    27     q.push_back(0);
    28     for(ll i=1;i<=n;i++){
    29         while( !q.empty() && q.front()<i-m ) q.pop_front();
    30         res = max(res,sum[i]-sum[q.front()]);
    31         while( !q.empty() && sum[q.back()]>=sum[i] ) q.pop_back();
    32         q.push_back(i);
    33     }
    34     printf("%lld
    ",res);
    35     return 0;
    36 }

    参考博客:here

  • 相关阅读:
    MySQL中表的基本操作1
    MySQL在表中加入记录
    GDB基本命令(整合)
    (转载)Linux的epoll模型
    不做采购,不知道销售有多蠢
    我的创业体会和大公司的做事比较
    需求问题排查
    我的创业体会和大公司的做事比较
    不同技术团队的配合问题及DevOps(不错的文章,来自infoq)
    不同技术团队的配合问题及DevOps(不错的文章,来自infoq)
  • 原文地址:https://www.cnblogs.com/wsy107316/p/13681095.html
Copyright © 2020-2023  润新知