最大子段和之环形问题

环形最大子段和

题目模型

  • 把模型一的线性变成环形。有一个修改,不允许区间为空。

问题分析

方法一:
  • 环形数组的连续最大子段和,有两种情况。

    1. 最大和的这个子段没有包含头尾。此时跟线型一样。
      • 定义dp[i]表示以a[i]结尾的最大子段和。
      • 转移方程:dp[i]=max(dp[i-1]+a[i],a[i])
    2. 最大和的这个子段包含了头尾。
      • 此时:最大子段和 = 整个序列和 - 最小子段和。
      • 此时最小子段和肯定是不包括头尾的,我们可以把原序列的每个元素乘以-1,然后求出最大子段和,即为原序列的不包括头、尾的最小子段和。
  • 然后比较两种情况的大小,输出大的那一个就行。

  • Code

    #include <bits/stdc++.h>
    const int maxn = 1e7+5,Inf=0x3f3f3f3f;
    typedef long long LL;
    LL a[maxn],b[maxn],dp[maxn];
    LL sum = 0,Max = 0,Min = 0;
    void Solve(){
        int n;scanf("%d",&n);
        srand(time(0));//随机种子
        for(int i=1;i<=n;++i){
            a[i]=rand()%10000-5000;//产生-5000~5000的随机数
            b[i]=-a[i];//原序列元素乘-1
            sum+=a[i];//序列之和
        }    
        for(int i=1;i<=n;++i){//对应情况1
            dp[i]=std::max(dp[i-1]+a[i],a[i]);
            Max=std::max(Max,dp[i]);
        }
        memset(dp,0,sizeof(dp));    
        for(int i=1;i<=n;++i){//对应情况2,求b的最大子段和,取反后为a的的最小子段和
            dp[i]=std::max(dp[i-1]+b[i],b[i]);
            Min=std::max(Min,dp[i]);
        }
        LL ans=std::max(Max,sum+Min);//sum+Min相当于序列和减去最小区间和
        printf("%lld\n",ans);
    } 
    int main(){
        Solve();
        return 0;
    }
    
方法二:
  • 可以用单调队列,具体做法见下一个模型。
posted @ 2020-06-15 14:49  ♞老姚♘  阅读(488)  评论(0编辑  收藏  举报