题意:给一个数组,问最多选一个子数组reverse一次之后最大的偶数位元素之和为多少。
题解:选一个长度为奇数的子数组reverse不改变答案。所以考虑reverse一个长度为偶数的子数组。大致乱搞思想:默认取偶数位时,选某一段区间连续取奇数位,最大和位多少,以及默认取奇数位时,选某一段连续取偶数位的最大和。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=2e5+4;
int n;
int a[N],t[N];
ll ans;
ll f[2][2][N>>1];//cur, used, pos
inline void smax(ll &x,ll y) {
x=x<y?y:x;
}
inline int read() {
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
inline void clear(int tot) {
for (register int i=1;i<=tot;++i) {
f[0][0][i]=0;
f[1][1][i]=0;
f[0][1][i]=0;
}
}
inline ll calc_od(int l,int r) {//default position is odd
int tot=0;
for (register int i=l;i<=r;++i) t[++tot]=a[i];
ll ret=0;
for (register int i=1;i<=tot;++i) {
smax(f[0][0][i],f[0][0][i-1]+t[(i<<1)-1]);
smax(f[1][1][i],max(f[1][1][i-1],f[0][0][i-1])+t[i<<1]);
smax(f[0][1][i],max(f[0][1][i-1],f[1][1][i-1])+t[(i<<1)-1]);
}
smax(ret,f[0][0][r>>1]);
smax(ret,f[1][1][r>>1]);
smax(ret,f[0][1][r>>1]);
clear(tot);
return ret;
}
inline ll calc_ev(int l,int r) {//default position is even
int tot=0;
for (register int i=l;i<=r;++i) t[++tot]=a[i];
ll ret=0;
for (register int i=1;i<=tot;++i) {
smax(f[0][0][i],f[0][0][i-1]+t[i<<1]);
smax(f[1][1][i],max(f[1][1][i-1],f[0][0][i-1])+t[(i<<1)-1]);
smax(f[0][1][i],max(f[0][1][i-1],f[1][1][i-1])+t[i<<1]);
}
smax(ret,f[0][0][r>>1]);
smax(ret,f[1][1][r>>1]);
smax(ret,f[0][1][r>>1]);
clear(tot);
return ret;
}
int main() {
// freopen("in.txt","r",stdin);
int kase=read();
while (kase--) {
ans=0;
n=read();
for (register int i=1;i<=n;++i) a[i]=read();
if (n&1) {
smax(ans,calc_od(1,n-1)+a[n]);
smax(ans,calc_ev(2,n)+a[1]);
} else {
smax(ans,calc_od(1,n));
smax(ans,calc_ev(2,n-1)+a[1]);
}
cout<<ans<<endl;
}
return 0;
}