• 环形最大子段和


    循环数组求最大子段和

    N个整数组成的循环序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的连续的子段和的最大值(循环序列是指n个数围成一个圈,因此需要考虑a[n-1],a[n],a[1],a[2]这样的序列)。当所给的整数均为负数时和为0。

    例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4,13。和为20。

    Input 第1行:整数序列的长度N(2 <= N <= 50000) 第2 - N+1行:N个整数 (-10^9 <= S[i] <= 10^9)

    Output 输出循环数组的最大子段和。

    Sample Input

    6 -2 11 -4 13 -5 -2

    Sample Output

    20 

    方法一:用前缀和和动态转移方程求解

        思路:输入ai数组,bi=-ai;

           将数组看成一个环状,那么最大子段和可能位于序列之中,也可能是序列的前缀和末尾之和;

           求出最大子段和,最小子段和(无论正负皆可)---->序列和减去最小子段和即为序列的前缀和末尾最大和;

           比较两个子段和输出最大值。

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int maxn=5e4+10;
    typedef long long ll;
    ll a[maxn],b[maxn],dp[maxn];
    int main() {
        int n;scanf("%d",&n);
        ll sum=0,Max=0,Min=0,ans=0;
        for(int i=1;i<=n;i++) {
            scanf("%lld",&a[i]);
            sum+=a[i];
            b[i]=-a[i];
        }
        for(int i=1;i<=n;i++) {
            dp[i]=max(dp[i-1]+a[i],a[i]);
            Max=max(Max,dp[i]);
        }
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++) {
            dp[i]=max(dp[i-1]+b[i],b[i]);
            Min=max(Min,dp[i]);
        }
        ans=max(Max,sum+Min);
        printf("%lld",ans);
        return 0;
    }
    

    方法二:双端队列求解(限制长度为n)

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    using namespace std;
    const int maxn=5e4*2+10;
    typedef long long ll;
    ll a[maxn*2],sum[maxn*2];
    int main() {
        int n;scanf("%d",&n);
        for(int i=1;i<=n;i++) {
            scanf("%lld",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
        for(int i=n+1;i<=n+n;i++) sum[i]=sum[i-1]+a[i-n];
        ll ans=-0x3f3f3f3f3f3f3f3f;
        deque<int> q;
        for(int i=1;i<n+n;i++) {
            while(!q.empty()&&sum[i-1]<sum[q.back()]) q.pop_back();
            while(!q.empty()&&i-q.front()>n) q.pop_front();
            q.push_back(i-1);
            if(sum[i]-sum[q.front()]>ans) ans=sum[i]-sum[q.front()];
        }
        printf("%lld",ans);
        return 0;
    }
    

    Max Sum of Max-K-sub-sequence(限制长度为k)

    Given a circle sequence A[1],A[2],A[3]......A[n]. Circle sequence means the left neighbour of A[1] is A[n] , and the right neighbour of A[n] is A[1].
    Now your job is to calculate the max sum of a Max-K-sub-sequence. Max-K-sub-sequence means a continuous non-empty sub-sequence which length not exceed K.

     Input

    The first line of the input contains an integer T(1<=T<=100) which means the number of test cases.
    Then T lines follow, each line starts with two integers N , K(1<=N<=100000 , 1<=K<=N), then N integers followed(all the integers are between -1000 and 1000).
    Output
    For each test case, you should output a line contains three integers, the Max Sum in the sequence, the start position of the sub-sequence, the end position of the sub-sequence. If there are more than one result, output the minimum start position, if still more than one , output the minimum length of them.Sample Input
    4
    6 3
    6 -1 2 -6 5 -5
    6 4
    6 -1 2 -6 5 -5
    6 3
    -1 2 -6 5 -5 6
    6 6
    -1 -1 -1 -1 -1 -1
    Sample Output
    7 1 3
    7 1 3
    7 6 2
    -1 1 1

    思路:同上一题的法二一样,可以用双端队列求解; 
    只不过把限制长度由n改为k;
       注意输入多组数据,初始化变量和数组。

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    using namespace std;
    const int maxn=5e4*2+10;
    typedef long long ll;
    ll a[maxn*2],sum[maxn*2];
    int main() {
        int n,T,k,l,r;scanf("%d",&T);
        for(int t=1;t<=T;t++) {
            scanf("%d%d",&n,&k);
            memset(sum,0,sizeof(sum));
            for(int i=1;i<=n;i++) {
                scanf("%lld",&a[i]);
                sum[i]=sum[i-1]+a[i];
            }
            for(int i=n+1;i<=n+k;i++) sum[i]=sum[i-1]+a[i-n];
            ll ans=-0x3f3f3f3f3f3f3f3f;
            deque<int> q;
            for(int i=1;i<n+k;i++) {
                while(!q.empty()&&sum[i-1]<sum[q.back()]) q.pop_back();
                while(!q.empty()&&i-q.front()>k) q.pop_front();
                q.push_back(i-1);
                if(sum[i]-sum[q.front()]>ans) {
                    ans=sum[i]-sum[q.front()];
                    l=q.front()+1;
                    r=i;
                }
            }
            if(l>n) l=l-n;
            if(r>n) r=r-n;
            printf("%lld %d %d
    ",ans,l,r);
        }
        return 0;
    }
    
  • 相关阅读:
    遇到的相关问题总结
    AI测试相关文章
    常用模块文档地址
    09-微服务接口:怎么用Mock解决混乱的调用关系
    03-思维方式:用一个案例彻底理解接口测试的关键逻辑
    1-基础:跳出细节看全局,接口测试到底是在做什么?
    21-Python并发编程之Futures
    使用原生php读写excel文件
    在for、foreach循环体中添加数组元素
    eval函数的坑
  • 原文地址:https://www.cnblogs.com/1999-09-21Karry-erfs/p/13153017.html
Copyright © 2020-2023  润新知