1051.最大的和(dp+前后缀分解)

传送门

 

 

 

 

 

 

输入样例:

1
10
1 -1 2 2 3 -3 4 -4 5 -5

输出样例:

13

样例解释

在样例中,我们取{2,2,3,-3,4}和{5}两个子段,即可得到答案。

 

这个题就是一个处理前后缀分解的题目

一般这种题目就是枚举分界点,这个题就是枚举一个i,然后就是前i个最大非空子段和加上i后面非空子段和

这个就需要预先处理出来这两个数组了

dp1[i]: 从1~i从前往后枚举,以数字a[i]结尾的,连续和的最大值
dp2[i]: 从n~i从后往前枚举,以数字a[i]结尾的,连续和的最大值

maxLeft[i]: 从1~i从前往后枚举,前1~i个数字连续和的最大值
maxRight[i]: 从n~i从后往前枚举,后n~i个数字连续和的最大值

状态计算如下:
dp1[i] = max( dp1[i - 1] + a[i], a[i])
maxLeft[i] = max(maxLeft[i - 1], dp1[i])

dp2[i] = max( dp2[i + 1] + a[i], a[i])
maxRight[i] = max(maxRight[i + 1], dp2[i])

最后枚举前后缀数组的分界点

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=3e5+100;
int g[maxn],f[maxn],a[maxn];
int l[maxn],r[maxn];
int main(){
    int t;
    cin>>t;
    while(t--){
        memset(l,0,sizeof(l));
        memset(r,0,sizeof(r));
        int n;
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        f[0]=-1e5,l[0]=-1e5;
        for(int i=1;i<=n;i++){
            f[i]=max(f[i-1]+a[i],a[i]);//f[i]指的是以i结尾的最大子段和 
            l[i]=max(l[i-1],f[i]);//l[i]指的是前i个不一定包含i的最大子段和,这个必须要连续 
        }
        g[n+1]=-1e5,r[n+1]=-1e5;
        for(int i=n;i>=1;i--){
            g[i]=max(g[i+1]+a[i],a[i]);
            r[i]=max(r[i+1],g[i]);
        }
        int ans=-1e5;
        for(int i=2;i<=n;i++){
            ans=max(ans,l[i-1]+r[i]);
        }
        cout<<ans<<endl;
    } 
} 

 

posted @ 2021-06-06 23:08  lipu123  阅读(122)  评论(0)    收藏  举报