环状两段最大子段和
Posted coder-cjh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了环状两段最大子段和相关的知识,希望对你有一定的参考价值。
Step 1
首先考虑链状的情况,也就是链状
++++++++-------------++++++++
P.S : ++ 表示使用的子段
可以考虑用中途相遇法,用 g[i] 表示以 ii 为结尾分界线,之前最大子段和,
以 h[i] 表示以 ii 为结尾分界线,之后最大子段和
那么答案也就是 g[i]+h[i+1] (不相交,所以要 +1 )
Step 2
如果是环状的呢?
+++---++++++----+++++++−−−++++++−−−−++++
俗话说得好正难则反,虽然不知道三段的怎么处理,但是可以通过不取的那两段,用总和去减,就可以得到答案
注意的一个坑点
-
如果我们头尾都不取,只剩下 11 个,显然是不符合条件的,所以要特判存在 11 的情况
因为有负权值的存在,所以设极值的时候不能设为0,要改为-inf
Step 3
#include<bits/stdc++.h> using namespace std; long long n,a[200005],f[200005],g[200005],b[200005],sum; bool check()//特判 int cnt=0; for(int i=1;i<=n;i++) if(a[i]>0)++cnt; return cnt!=1; int main() scanf("%lld",&n); for(int i=1;i<=n;i++) scanf("%lld",&a[i]),sum+=a[i]; f[0]=g[0]=-0x7fffffff;//边界 for(int i=1;i<=n;i++)//往前继承 f[i]=max(f[i-1]+a[i],a[i]); g[i]=max(g[i-1],f[i]); f[n+1]=b[n+1]=-0x7fffffff;//往后继承 for(int i=n;i;i--) f[i]=max(f[i+1]+a[i],a[i]); b[i]=max(b[i+1],f[i]); long long ans=-0x7fffffff;//统计第一种情况 for(int i=1;i<=n;i++)ans=max(ans,b[i+1]+g[i]); if(!check())return cout<<ans<<endl,0;//特判 f[0]=g[0]=0x7fffffff; for(int i=1;i<=n;i++)//往前 f[i]=min(a[i],f[i-1]+a[i]); g[i]=min(g[i-1],f[i]); b[n+1]=f[n+1]=0x7fffffff; for(int i=n;i;i--)//往后 f[i]=min(f[i+1]+a[i],a[i]); b[i]=min(b[i+1],f[i]); long long ans2=0x7fffffff;//第二种答案,求出最小的再用总和去减 for(int i=1;i<=n;i++)ans2=min(ans2,b[i+1]+g[i]); if(sum-ans2==0)ans2=-0x7fffffff;//如果得到的是总和就不合题意 else ans2=sum-ans2;//否则得到最小值 cout<<max(ans,ans2)<<endl;//输出最大值 return 0;
以上是关于环状两段最大子段和的主要内容,如果未能解决你的问题,请参考以下文章