这题比较有趣。
首先呢,我们可以发现,当选择的区间长度为奇数时,答案是不会改变的,所以我们必须选择长度为偶数的区间。其次我们可以观察到一个性质,每选择一个区间进行修改时,每一个偶数位置只可能变成它的前一位和后一位,所以我们是不是可以比较每一个位置究竟是变成前一位还是后一位呢?那然后我们该怎么实现呢,我们可以计算每一次交换的贡献,然后求一个最大子段和,这样就可以了。不懂可以仔细想一想。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<list>
#include<cmath>
#include<map>
#include<vector>
#define int long long
using namespace std;
int t,n,a[200005],num,sum,maxx;
signed main()
{
cin>>t;
while(t--)
{
int ans1=0,ans2=0,ans=0;
vector<int>v,e;
num=0;
scanf("%lld",&n);
for(int i=0;i<n;i++)
{
scanf("%lld",&a[i]);
}
if(n==1)
{
printf("%lld\n",a[0]);
continue;
}
for(int i=0;i<n;i+=2)
{
num+=a[i];
}
//ans=num;
for(int i=1;i<n;i+=2)
{
v.push_back((a[i]-a[i-1]));
}
for(int i=2;i<n;i+=2)//vector尽量用-1,如果位置+1可能会造成越界
{
e.push_back((a[i-1]-a[i]));
}
maxx=-0x3fffffff;
sum=0;
for(int i=0;i<v.size();i++)//接下来是求两次子段和,分别代表前面和后面
{
sum+=v[i];
maxx=max(maxx,sum);
if(sum<0)
{
sum=0;
}
}
int k=max((int)0,maxx);
maxx=-0x3fffffff;
sum=0;
for(int i=0;i<e.size();i++)
{
sum+=e[i];
maxx=max(maxx,sum);
if(sum<0)sum=0;
}
ans=num+max(max((int)0,k),max((int)0,maxx));//我判断的写法丑了一些,大家按照自己的想法来就行
printf("%lld\n",ans);
}
}