这个题有一个很明显的O(n4)的暴力dp方程,我们考虑优化这个dp:
fi=max(sumi−sumj+sumk−suml)(j<=i,k<=j,l<=k)
后两个sumk−suml的值可以通过经典的最大子段和的dp做出来,记为mxj
然后就是这样了:
fi=max(sumi−sumj+mxj)(j<=i)
提出来sumi:
fi=sumi+max(−sumj+mxj)(j<=i)
后面那一段可以记录一个变量来O(1)转移,然后时间就是O(n)
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#define ll long long
using namespace std;
inline int read(){
int x=0;char ch=' ';int f=1;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
inline int lowbit(int x){
return x&-x;
}
int n;
int a[100001];
int mx[100001];
int mxmx[100001];
int t[100001];
int sum[100001];
int f[100001];
int nm[100001];
int main(){
freopen("safe.in","r",stdin);
freopen("safe.out","w",stdout);
n=read();
int num=0;
for(int i=1;i<=n;i++){
a[i]=read();
sum[i]=sum[i-1]+a[i];
num+=a[i];
if(num>0){
mx[i]=num;
}
else{
num=0;
}
}
for(int i=1;i<=n;i++){
if(a[i]<0&&mx[i]==0){
mx[i]=a[i];
}
}
int now=-0xfffffff;
for(int i=1;i<=n;i++){
now=max(now,mx[i]);
mxmx[i]=now;
}
for(int i=1;i<=n;i++){
nm[i]=mxmx[i]-sum[i];
}
now=0;
int ans=-0xfffffff;
for(int i=1;i<=n;i++){
f[i]=sum[i]+now;
now=max(now,nm[i]);
ans=max(ans,f[i]);
}
printf("%d",ans);
return 0;
}