• 51nod 1050 循环数组最大子段和 单调队列优化DP


    题目链接: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1050

    这个呢,这个题之前 求一遍最大值  然后求一遍最小值

    最后结果 res = max( MAX,  SUM - MIN );

    但是 这种题如果 要求 变成 最长长度为len的最大子段和,这种思路就会受限制

    换一种想法, 让你求最大长度为len的最大字段和 那么 你可以维护一个前缀和 

    然后结果就是 max( sum[i] - min(sum[j]) , i-len <= j <= i-1 && 1<=i <= 2*n)

    然后这么看来 是n^2的dp,那么如何优化呢。

    可以预处理  长度为len的区间的最小值  然后对于每个i 查询前面区间长度为 len 的最小值 然后 sum[i] - sum[j]即可 ,(类似RMQ,或者线段树,树状数组都可以做 )复杂度 O(nlogn)

    也可以 维护单调队列  单调队列要保证 两点:

    1.  队内元素的位置 要符合 i的区间要求 即 i-len <=que[j]<=i-1

    2. 单调性, 队列内的元素 尽可能小,维护一个单调非递增队列

    #include <iostream>
    #include <cstdio>
    #include <string.h>
    #include <string>
    #include <algorithm>
    using namespace std;
    const int N = 5e4+10;
    typedef long long ll;
    
    int n; ll s[N<<1],sum[N<<1];
    int q[N<<1];
    
    int main ()
    {
        cin >> n; int len = n;
        for(int i=1;i<=n;i++) {
            cin >> s[i];
            s[i+n] = s[i];
        }
        n<<=1;
        for(int i=1;i<=n;i++) {
            sum[i] = sum[i-1] + s[i];
        }
        ll res = 0;
        int st=0,ed=0;
    
        for(int i=1; i<=n; i++) {
            if(i <= len)
                res = max(res, sum[i]); 
            // sum[i] - min(sum[j]),  (i-len<=j<=i-1)
            while (st < ed && q[st] < i-len) 
                st++; 
            res = max(res, sum[i] - sum[q[st]]);
            while (st < ed && sum[i] <= sum[q[ed-1]]) 
                ed--;
            q[ed++] = i;
        }
        cout << res <<endl;
        return 0;
    }
  • 相关阅读:
    LeetCode (Two Sum & Add Two nums)
    打包时记录编译开始时间并在App中获取
    CocoaPods
    不知所云
    苹果审核相关内容
    iOS权限的一些备注
    触发网络权限弹窗的一些特别方式记录
    iOS13和iOS14里面访问相册选取图片的两种方式的区别
    @Configuration@Bean
    ACID
  • 原文地址:https://www.cnblogs.com/Draymonder/p/9536681.html
Copyright © 2020-2023  润新知