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; } }

浙公网安备 33010602011771号