传送门
题意:
简单说
就是给个序列
求和最大的两段
且序列头可接尾
解法:
若不考虑环
则可对每一个位置
分成其前一段和其后一段
求其前一段与后一段的最大最段和相加
找到最大的值
在考虑环的情况
可以把原问题转化为求中间最小的两段
再用序列全部的和 减去 最小的两段
为了偷懒
直接将序列所有数取相反数
然后按照第一种做法做
当然序列中只有一个正数和无正数时这么做就错了
因为求出来的值需要至少有一个序列为空
此时我们就并不需要做考虑环的操作
直接输出不考虑环的值就行
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#define inf 2000000000
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dwn(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
typedef long long ll;
int n,ans1,ans2,sum=0,tot=0,a[200010],f[200010],g[200010];
int solve()
{
int ans=-inf;
rep(i,1,n) f[i]=max(f[i-1],0)+a[i];
dwn(i,n,1) g[i]=max(g[i+1],0)+a[i];
rep(i,2,n) f[i]=max(f[i-1],f[i]);
dwn(i,n-1,1) g[i]=max(g[i+1],g[i]);
rep(i,1,n-1) ans=max(ans,f[i]+g[i+1]);
return ans;
}
int main()
{
scanf("%d",&n);
rep(i,1,n)
{
scanf("%d",&a[i]);
sum+=a[i],tot+=(a[i]>0);
}
ans1=solve();
if(tot<=1)
{
printf("%d
",ans1);
return 0;
}
rep(i,1,n) a[i]=-a[i];
ans2=sum+solve();
printf("%d
",max(ans1,ans2));
return 0;
}