标签:如何 mes for std void int swap amp 快速
http://www.51nod.com/Challenge/Problem.html#problemId=1254
最终答案只有2种情况
1、不交换最大,相当于随便交换2个在最大子段和里的数。
2、把一个原本不在最大子段和里的数换到最大子段和里。
第1种情况就跑一遍求最大子段和就好
对于第2种情况:
假设现在要交换第i个和第k个 (k < i),并且第k个是我们想要的,第i个是要换走的。
定义\(g[i]\)表示把\(a[i]\)与\(a[k]\)交换之后,以新的第i个数为最后一个数字的最大子段和
定义\(r[i]\)表示以i为第一个数字的最大子段和
那么在交换的2个数是换走后一个、选用前一个的前提下,最大子段和可以表示为\(max(g[i]+r[i+1])\)
对于 i > k 的情况,也就是交换的2个数是换走前一个、选用后一个,把a数组逆序再做一遍即可。
如何快速求出\(g[i]\) ?
\(g[i]=max_{k=1}^{i-2}(a[k] + max_{h=k+1}^{i-1}(\sum_{j=h}^{i-1}a[j]))\), 子段长度 \(\leq\) 2
\(g[i]=max_{j=1}^{i-1} a[j]\),子段长度 \(=1\)
所以
\(g[i+1]=max(max_{k=1}^{i-1}(a[k]+max_{h=k+1}^i(\sum_{j=h}^ia[j])),max_{j=1}^i a[j])=max(g[i]+a[i],max_{j=1}^i a[j])\)
#include<cstdio>
#include<algorithm>
using namespace std;
#define N 500003
int n,a[N];
long long r[N];
long long ans=-1e17;
void solve()
{
for(int i=n;i;--i) r[i]=max(0ll,r[i+1]+a[i]);
int m=a[1];
long long g=a[1];
for(int i=2;i<=n;++i)
{
ans=max(ans,g+r[i+1]);
m=max(m,a[i]);
g=max(g+a[i],1ll*m);
}
}
int main()
{
scanf("%d",&n);
long long now=0;
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
now+=a[i];
if(now<0) now=0;
ans=max(ans,now);
}
solve();
int t=n/2;
for(int i=1;i<=t;++i) swap(a[i],a[n-i+1]);
solve();
printf("%lld",ans);
}
标签:如何 mes for std void int swap amp 快速
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/14659526.html