序列双段最大子段和问题
(也许很水但蒟蒻刚刚学dp就来记录一下)
题意就是求序列中的任意两段的最大子段和最大。
我们先预处理出来前缀和,方便求最大子段和。
对于每一个i都求一遍1到i的最大子段和,即:
pre[1]=a[1]; minn=min(0,a[1]); for(int i=2;i<n;i++){ minn=min(minn,a[i]); pre[i]=max(pre[i-1],a[i]-minn); }
其中,a数组是前缀和,直接处理的。
那么,我们再对n到1的每一个i求一遍最大子段和,即:
post[n]=a[n]-a[n-1]; maxn=a[n]; for(int i=n-1;i>1;i--){ maxn=max(maxn,a[i]); post[i]=max(post[i+1],maxn-a[i-1]); }
那么,接下来我们要做些什么?
枚举每一个i,从1到n-1,求出前i个数的最大子段和和i第i+1个数到n的最大子段和之和的最大值。
即:
ans=-inf; for(int i=1;i<n;i++)ans=max(ans,pre[i]+post[i+1]); printf("%d ",ans);
完整代码:
#include<cstdio> #include<iostream> #include<cstring> #define inf 2147483647 using namespace std; int t,n,a[50001]; int maxn,minn,pre[50001]; int post[50001],ans; inline void solve(){ pre[1]=a[1]; minn=min(0,a[1]); for(int i=2;i<n;i++){ minn=min(minn,a[i]); pre[i]=max(pre[i-1],a[i]-minn); } post[n]=a[n]-a[n-1]; maxn=a[n]; for(int i=n-1;i>1;i--){ maxn=max(maxn,a[i]); post[i]=max(post[i+1],maxn-a[i-1]); }ans=-inf; for(int i=1;i<n;i++)ans=max(ans,pre[i]+post[i+1]); printf("%d ",ans); memset(pre,0,sizeof(pre)); memset(post,0,sizeof(post)); } int main(){ scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i=1;i<=n;++i)scanf("%d",&a[i]),a[i]+=a[i-1]; solve(); } return 0; }