仔细观察一下,发现要求的就是环上两段最大子段和,因为你总是可以通过翻转把这两段拼在一起。
这是一个经典问题(Luogu),直接正反贪心一遍拼在一起,取相反数后再做一次即可。
需要注意的是可能要特判全是负数的情况。
// ==================================== // author: M_sea // website: https://m-sea-blog.com/ // ==================================== #include <bits/stdc++.h> #define file(x) freopen(#x".in","r",stdin); freopen(#x".out","w",stdout) #define debug(...) fprintf(stderr,__VA_ARGS__) using namespace std; typedef long long ll; int read() { int X=0,w=1; char c=getchar(); while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); } while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar(); return X*w; } const int N=200000+10; int n,a[N],cnt=0; ll sum=0; ll f[N],g[N]; ll calc() { for (int i=1;i<=n;++i) f[i]=max(f[i-1],0ll)+a[i]; for (int i=n;i>=1;--i) g[i]=max(g[i+1],0ll)+a[i]; for (int i=1;i<=n;++i) f[i]=max(f[i-1],f[i]); for (int i=n;i>=1;--i) g[i]=max(g[i+1],g[i]); ll res=-1e18; for (int i=1;i<n;++i) res=max(res,f[i]+g[i+1]); return res; } int main() { n=read(); for (int i=1;i<=n;++i) a[i]=read(),sum+=a[i],cnt+=(a[i]>0); if (!cnt) { int ans=-1e18; for (int i=1;i<=n;++i) ans=max(ans,a[i]); printf("%d\n",ans); return 0; } ll ans1=calc(); for (int i=1;i<=n;++i) a[i]=-a[i]; ll ans2=calc(); if (!ans2) ans2=-1e18; printf("%lld\n",max(ans1,sum+ans2)); return 0; }